Plugins
Un plugin es la manera que tiene un paquete de Composer de añadir páginas, scripts, hojas de estilo, textos y rutas a un panel, sin que la aplicación tenga que copiar nada. La aplicación decide en qué paneles lo activa. Disponible desde la 1.2.
Panel::make('admin')
->plugins([BillingPlugin::make()])Un mismo plugin no se puede registrar dos veces en el mismo panel: Arrel lanza una excepción.
Escribir un plugin
Un plugin extiende Arrel\Plugins\Plugin. Solo hace falta id(); el resto de métodos devuelven una lista vacía si no los sobrescribes.
use Arrel\Pages\CustomPage;
use Arrel\Plugins\Plugin;
final class BillingPlugin extends Plugin
{
public static function make(): self
{
return new self;
}
public function id(): string
{
return 'billing';
}
public function customPages(): array
{
return [
CustomPage::make('billing', __('billing::billing.navigation_label'))
->icon('credit-card')
->visible(fn (): bool => Gate::allows('billing.manage')),
];
}
public function scripts(): array
{
return [asset('vendor/billing/billing.js')];
}
public function stylesheets(): array
{
return [asset('vendor/billing/billing.css')];
}
public function translations(): array
{
return ['title' => __('billing::billing.title')];
}
}| Método | Qué aporta |
|---|---|
id() | El identificador del plugin. Hace de prefijo de sus textos y de sus rutas. |
customPages() | Páginas personalizadas, con su entrada de navegación. |
scripts() | Scripts que el panel carga después de los suyos. |
stylesheets() | Hojas de estilo que el panel carga después de las suyas. |
translations() | Textos para el frontend. |
El panel lee estos métodos cada vez que sirve una página, no cuando se registra el plugin. Por eso el orden de plugins() y customPages() en la definición del panel no importa, y __() ya devuelve el texto en el idioma del usuario.
La página
El script del plugin registra su página igual que lo haría la aplicación, normalmente con registerMountablePage y su propia instancia de Vue. Si el paquete usa el kit de componentes de Arrel, lo incorpora a su propio build.
Si construyes el script con Vite en modo librería, define process.env.NODE_ENV. Vite no lo sustituye en ese modo y Vue lo lee: sin el define, el script falla al cargarse y la página nunca se registra.
// vite.config.js
export default defineConfig({
define: {
'process.env.NODE_ENV': JSON.stringify('production'),
},
build: {
lib: { entry: 'resources/js/main.ts', formats: ['es'], fileName: () => 'billing.js' },
},
})Textos
Los textos de translations() llegan a window.Arrel.translations con el prefijo del identificador del plugin. Así, title de un plugin billing es billing.title, y nunca sustituye un texto del panel.
const title = window.Arrel.translations?.['billing.title']Los textos de PHP (mensajes de validación, la navegación) los carga el paquete con loadTranslationsFrom(), como cualquier paquete de Laravel. Arrel no interviene.
Rutas
ArrelRoutes::plugin() registra las rutas del paquete con la misma pila de middleware que la API autenticada de Arrel, incluidos arrel.middleware y arrel.authenticated_middleware. Si tu aplicación identifica el tenant en ese middleware, las rutas del plugin ya lo tienen.
use Arrel\Http\ArrelRoutes;
ArrelRoutes::plugin('billing', function (): void {
Route::get('/', [BillingController::class, 'context'])->name('context');
Route::post('checkout', [BillingController::class, 'checkout'])->name('checkout');
});Las rutas quedan en /arrel-plugins/{id} y se llaman arrel.plugins.{id}.*: el ejemplo sirve GET /arrel-plugins/billing con el nombre arrel.plugins.billing.context.
El prefijo está fuera de /arrel/api y del prefijo del panel a propósito. Las rutas de Arrel que cuelgan de ahí capturan cualquier ruta, y el orden en que Laravel arranca los paquetes no está garantizado: una ruta que un paquete registrara después quedaría tapada.
Como en cualquier endpoint propio, autoriza cada petición. Que visible() oculte la entrada de navegación no impide que alguien llame a la ruta a mano.