/ziglite

A Laravel named routes integration for Javascript

Primary LanguagePHPApache License 2.0Apache-2.0

Ziglite - A Laravel named routes integration for Javascript

GitHub Actions Workflow Status Packagist Version Packagist Downloads NPM Version NPM Downloads

What is Ziglite?

Ziglite provides a way for Laravel developers to use their route names in the front end.
This package is inspired by, and a lightweight minimalistic alternative to, the excellent and feature-rich Ziggy by Tighten.

Quick Start

Install Ziglite in your Laravel application or package with Composer:

composer require spatian-dev/ziglite
yarn install ziglite

Include the default directive in your Blade @ziglite("*"):

⚠️Warning: This will expose all the named routes and their parameters in your application to the front-end, which may not be desirable.
See Route filtering to learn about including and excluding routes.

Configure the javascript helpers:

import { configureRouter } from 'ziglite';
configureRouter(ziglite_data);

Use the route() helper to transform a named route to a URL:

import { route } from 'ziglite';
route('users.update', {user: 5});

⚠️Warning: Ziglite does not support Encoded Forward Slashes. See strict mode for more information.

Supported Laravel Versions

Laravel Supported
10.x
11.x

Why Ziglite?

Ziglite is intended to be a simplified alternative to Ziggy. By omitting some of Ziggy's more advanced features, Ziglite offers a focused feature set aimed at ease of use. One notable difference is in filtering: Ziglite opts for a simplified and stricter approach by default.

Additionally, Ziglite boasts seamless integration into Laravel packages, providing developers with the ability to:

  • Define custom aliases for the default Blade directive
  • Utilize custom output generators
  • Exert greater control over route filtering.

We hope Ziglite delivers simplicity and versatility for your Laravel projects and packages.
If you have ideas or suggestions, please see Contributing.

Usage in a Package

Register Ziglite's service provider inside the register() method of your package's service provider:

$this->app->register(\Spatian\Ziglite\Providers\ZigliteServiceProvider::class);

You can then use the package the same way you would from a regular Laravel Application.

Route Filtering

Ziglite only includes named routes that match explicitly provided filters. The filtering is based on pattern-matching capabilities provided by Laravel's Str helper.

Exclusion can be defined by starting the pattern with a !

ℹ️ Exclusions patterns are always prioritized over inclusion patterns, regardless of the order in which they are defined.

For example:

  • * will include all named routes
  • !users.* will exclude all named routes starting with users.
  • !*.index will exclude all named routes ending with .index
  • home will include the route named home

You can provide as many inclusion or exclusion patterns as necessary

use Spatian\Ziglite\Routes\Manifest;

new Manifest(["*", "!admin.*", "!api.*"]);

// in blade
@ziglite(["*", "!admin.*", "!api.*"]);

The Routes Manifest

The core of Ziglite revolves around the \Spatian\Ziglite\Routes\Manifest class. This class collects and caches your application's named routes, and generates a list of named routes that match the provided filters.

Filters

By default, a Manifest instance will only include named routes that match the provided filters. If no filters are provided, then no routes are included.
Filtering patterns can be provided as the first argument to the constructor.

use Spatian\Ziglite\Routes\Manifest;

new Manifest(); // No routes included

new Manifest("*"); // A single pattern
new Manifest(["*", "!admin.*", "!api.*"]); // A list of patterns

See Route filtering to learn more about filtering.

Custom Origin

You can specify a custom origin to be included in the manifest.

use Spatian\Ziglite\Routes\Manifest;

new Manifest(base: 'https://example.test');

Caching

The Manifest class caches previously generated manifests for the duration of a request. Subsequent calls with the same filtering patterns simply return the previously calculated result.
If this is not desirable, you can clear this cache using :

use Spatian\Ziglite\Routes\Manifest;

Manifest::clearRoutes();

Serializing to JSON

The Manifest class implements JsonSerializable and a toJson() function to simplify serializing to JSON.

use Spatian\Ziglite\Routes\Manifest;

json_encode(new Manifest());
(new Manifest())->toJson();

The Blade Directive

By default, Ziglite defines a @ziglite blade directive. This directive uses the default JavascriptDataTagGenerator to include a manifest as a JSON object in a blade.
The JSON object is assigned to a ziglite_data variable on the window global.

// home.blade.php
@ziglite("*")
// home.js
console.log(ziglite_data);
/*
    Should print an object similar to :

    {
        base: ...,
        defaults: { ... },
        routes: [ ... ],
    }
*/

Custom Directives and Custom Generators

You can define your custom generators by implementing the OutputGeneratorInterface. This requires implementing a make() function that generates the output as a string.

make(array|string $filters = [], string $base = null, string $nonce = ''): string
  • $filters pattern or list of patterns for filtering
  • $base custom origin to be included in the output
  • $nonce a CSP nonce to be included in the output.

You can also define a custom blade directive that uses your custom generator. In your AppServiceProvider:

app('ziglite')->setupBladeDirective('mydirective', new MyCustomOutputGenerator());

The Front-end Helpers

The javascript library is published to a separate NPM package.

yarn install ziglite

By default, Ziglite does not globally import its javascript helpers. Instead, it defers to the developer to include them and use them as they see fit.
The library does, however, create an internal default instance of the Router class. You can interact with this instance through the helper functions below.

The configureRouter() helper

Use this function to set the configuration for the default Router instance.

import { configureRouter } from 'ziglite';

configureRouter(ziglite_data);

configureRouter({
    strict: false,
    absolute: true,
    base: 'https://example.test',
});

The route() and hasRoute() helpers

The route() function transforms a named route to a URL using the default Router instance. This function works similarly to Laravel's route().

import { route } from 'ziglite';

route('home');

route('users.show', {user: 5});

The hasRoute() function checks if the default Router instance has a configured route that matches the given name.

import { hasRoute } from 'ziglite';

hasRoute('home');   // assuming a route named 'home' exits, return true;
hasRoute('inexistant');   // assuming no route named 'inexistant' exits, return false;

Default Parameters

Ziglite supports Laravel's default parameters.

import { route } from 'ziglite';
/*
    Given a route named 'users.show' defined as /{locale}/users/{user},
    and configured route default ['locale' => 'en']
*/
route('users.show', {user: 5}); // https://example.test/en/users/5

Generating Absolute URLs

By default, Ziglite will generate relative URLs. To generate absolute URLs instead, set the absolute configuration to true;

import { configureRouter, route } from 'ziglite';

configureRouter({
    absolute: true,
    base: 'https://example.test',
    // ...
});

route('users.show', {user: 5}); // https://example.test/users/5

Extra Query Parameters

Ziglite will automatically add any unmatched parameters as a query string to the resulting URL:

import { route } from 'ziglite';

route('users.show', {user: 5, extra: 2}); // https://example.test/users/5?extra=2

If you need to add query-string parameters that have the same name as your route's parameter, you can do so under a _query object:

import { route } from 'ziglite';

route('users.show', {
    user: 5,
    extra: 2,
    _query: {
        user: 'Tony'
    },
}); // https://example.test/users/5?extra=2&user=Tony

By default, booleans are converted to integers

import { route } from 'ziglite';

route('users.show', {
    user: 5,
    locked: true,
}); // https://example.test/users/5?locked=1

The Router Class

The Router provides the core of Ziglite's javascript functionality.
If you would like to use Ziglite's features without modifying the default instance, you might create your own Router instance:

import { Router } from 'ziglite';

const config = {
    absolute: true,
    base: 'https://example.test',
    defaults: {
        locale: 'en',
    },
    routes: [ /* ... */],
};

const myRouter = new Router();
myRouter.config = config;

// or
const myRouter = new Router(config);

// check if the given named route exists
myRouter.has('home');

// transform the given named route and parameters to a URL
myRouter.compile('users.show', {user: 5}); // https://example.test/users/5

Strict Mode

Ziglite does not support Encoded Forward Slashes. This has historically been buggy, inconsistent and overall not a reliable feature to implement.
By default, Ziglite will issue a warning in your console if it encounters a forward slash, plain (/) or encoded (%2F), in a parameter value.
If you enable strict mode, Ziglite will throw an error instead.

import { configureRouter, route } from 'ziglite';

configureRouter({
    strict: true,
    // ...
});

route('users.show', {user: 'test/test'}); // throws

Contributing

Please consult the contribution guide.

Credits

License

Ziglite is free and open-source software released under the Apache 2.0 license. See LICENSE for more information.