Skip to content

Instantly share code, notes, and snippets.

@mwikala
Last active December 30, 2022 04:50
Show Gist options
  • Save mwikala/5fd492447263fcf3a39dac7456e1ada9 to your computer and use it in GitHub Desktop.
Save mwikala/5fd492447263fcf3a39dac7456e1ada9 to your computer and use it in GitHub Desktop.
Generate Ziggy.js Typescript Definitions — Laravel 9 and Vite
// Copied from https://gist.github.com/iDevelopThings/aa0a288a4075371d875782c72f2c0389
// This command will generate a file in resources/js/ called ziggy-shims.d.ts
// Make sure to install @types/ziggy-js for the type definitions used by the file generated
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Log;
use Tightenco\Ziggy\Ziggy;
class GenerateZiggyTypescriptDefinitions extends Command
{
protected $signature = 'ziggy:typescript';
protected $description = 'Generate TS definitions for ziggy';
protected $files;
public function __construct(Filesystem $files)
{
parent::__construct();
$this->files = $files;
}
public function handle()
{
$path = './resources/js/ziggy-shims.d.ts';
$generatedRoutes = $this->generate();
$this->makeDirectory($path);
$this->files->put(base_path($path), $generatedRoutes);
$this->info('File generated!');
}
private function generate(): string
{
$ziggy = (new Ziggy(false, null));
$collectedRoutes = collect($ziggy->toArray()['routes']);
$routes = $collectedRoutes
->map(function ($route, $key) {
$methods = json_encode($route['methods'] ?? []);
return <<<TYPESCRIPT
"{$key}": {
"uri": "{$route['uri']}",
"methods": {$methods},
},
TYPESCRIPT;
})
->join("\n");
$params = $collectedRoutes->map(function ($route, $key) {
$matches = [];
preg_match_all('/(?<=\{)(.*?)(?=\})/', $route['uri'], $matches);
if (!count($matches) || !count($matches[0])) {
return <<<TYPESCRIPT
"{$key}": {
},
TYPESCRIPT;
} else {
$unencodedParams = collect($matches[0])->reduce(function ($carry, $match) {
$carry[$match] = $match;
return $carry;
}, []);
$params = json_encode($unencodedParams);
return <<<TYPESCRIPT
"{$key}":
{$params}
,
TYPESCRIPT;
}
})
->join("\n");
//Log::debug($params);
return <<<TYPESCRIPT
import {Config, Router} from "ziggy-js";
type LaravelRoutes = {
{$routes}
}
const LaravelParams = {
${params}
}
declare global {
declare interface ZiggyLaravelRoutes extends LaravelRoutes {}
declare function route(): Router;
declare function route<RouteKey extends keyof LaravelRoutes>(name: RouteKey, params?: LaravelRoutes[RouteKey], absolute?: boolean, customZiggy?: Config): string;
}
export { LaravelRoutes, LaravelParams };
TYPESCRIPT;
}
protected function makeDirectory($path)
{
if (!$this->files->isDirectory(dirname(base_path($path)))) {
$this->files->makeDirectory(dirname(base_path($path)), 0755, true, true);
}
return $path;
}
}
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
import { exec } from 'child_process';
export default defineConfig({
plugins: [
laravel({
input: 'resources/js/app.tsx',
refresh: true,
}),
react(),
ziggy(),
],
});
function ziggy(paths: Array<string> = ["routes/**/*.php"], enabled: boolean = true): import('vite').Plugin {
const generate = () => {
exec('php artisan ziggy:typescript', (_, stdout, __) => console.log(stdout));
}
return {
name: 'ziggy-vite-plugin',
async buildStart() {
if (! enabled) {
return;
}
(await import ('chokidar')).watch(paths).on('change', (path) => {
console.log(`Ziggy: ${path} changed, regenerating...`);
generate();
})
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment