tests / lint (push) Successful in 1m6s
tests / feature (8.4) (push) Successful in 1m18s
tests / feature (8.5) (push) Successful in 1m17s
tests / browser (chrome, chromium) (push) Successful in 3m27s
tests / browser (firefox, firefox) (push) Successful in 4m57s
tests / browser (safari, webkit) (push) Successful in 5m29s
php artisan view:cache compiles every view in the package's namespace, the showcase's pages included, but the showcase:: component prefix was only registered while the showcase was enabled. In production, where it is off, view:cache failed with "Unable to locate a class or view for component [showcase::example]" and an application caching its views on start would not boot. The prefix is now always registered; the routes still are not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
196 lines
7.7 KiB
PHP
196 lines
7.7 KiB
PHP
<?php
|
|
|
|
namespace NoNameWeb\LivewireMaterial;
|
|
|
|
use Illuminate\Contracts\View\Factory;
|
|
use Illuminate\Support\Facades\Blade;
|
|
use Illuminate\Support\Facades\Route;
|
|
use Illuminate\Support\Facades\View;
|
|
use Illuminate\Support\ServiceProvider;
|
|
|
|
class LivewireMaterialServiceProvider extends ServiceProvider
|
|
{
|
|
public function register(): void
|
|
{
|
|
$this->mergeConfigFrom(__DIR__.'/../config/livewire-material.php', 'livewire-material');
|
|
|
|
$this->disableBladeIconsComponent();
|
|
$this->registerErrorViews();
|
|
$this->registerMailComponents();
|
|
}
|
|
|
|
public function boot(): void
|
|
{
|
|
$this->loadViewsFrom(__DIR__.'/../resources/views', 'livewire-material');
|
|
$this->loadTranslationsFrom(__DIR__.'/../lang', 'livewire-material');
|
|
|
|
$this->registerComponents();
|
|
$this->registerPagination();
|
|
$this->registerShowcase();
|
|
|
|
if ($this->app->runningInConsole()) {
|
|
$this->commands([
|
|
Console\SchemeCommand::class,
|
|
]);
|
|
|
|
$this->publishes([
|
|
__DIR__.'/../config/livewire-material.php' => config_path('livewire-material.php'),
|
|
], 'livewire-material-config');
|
|
|
|
$this->publishes([
|
|
static::errorViewPath().'/errors' => resource_path('views/errors'),
|
|
], 'livewire-material-errors');
|
|
|
|
$this->publishes([
|
|
static::mailComponentPath().'/html' => resource_path('views/vendor/mail/html'),
|
|
static::mailComponentPath().'/text' => resource_path('views/vendor/mail/text'),
|
|
], 'livewire-material-mail');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The anonymous components. Blade names their view namespace after a hash of this string, and
|
|
* compiled views keep that name, so it stays written the way it always was.
|
|
*/
|
|
public static function componentPath(): string
|
|
{
|
|
return __DIR__.'/../resources/views/components';
|
|
}
|
|
|
|
/**
|
|
* The error-view root: a folder holding only `errors/`.
|
|
*/
|
|
public static function errorViewPath(): string
|
|
{
|
|
return dirname(__DIR__).'/resources/views/error-pages';
|
|
}
|
|
|
|
/**
|
|
* The mail component root, laid out like the framework's: `html/` and `text/`.
|
|
*/
|
|
public static function mailComponentPath(): string
|
|
{
|
|
return dirname(__DIR__).'/resources/views/mail';
|
|
}
|
|
|
|
/**
|
|
* Append the error-view root to `view.paths`, after the application's own.
|
|
*
|
|
* The exception handler replaces the `errors` namespace each time it renders an HTTP
|
|
* exception, with every entry of `view.paths` plus `/errors` and the framework's views last
|
|
* (RegisterErrorViewPaths), so a namespace added with addNamespace() is gone by then; only a
|
|
* view path survives. That config is read at render time, but also once when the view
|
|
* finder is built: appended here, in register(), before any boot() resolves the view
|
|
* factory, the finder and `view:cache` see the same paths the handler does. Appending keeps
|
|
* `view.paths[0]` — Laravel's viewPath() — the application's, and puts the application's
|
|
* own `resources/views/errors` first. Idempotent, since a cached config already holds it.
|
|
*/
|
|
protected function registerErrorViews(): void
|
|
{
|
|
$paths = (array) config('view.paths', []);
|
|
|
|
if (! in_array(static::errorViewPath(), $paths, true)) {
|
|
config(['view.paths' => [...$paths, static::errorViewPath()]]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Put the package's mail header and message after the application's own mail components,
|
|
* when `livewire-material.mail.components` asks for it. Off by default: it changes every
|
|
* Markdown mail the application sends, theme or not, and the framework reads
|
|
* `mail.markdown.paths` once, when the Markdown renderer is first made — after register().
|
|
*/
|
|
protected function registerMailComponents(): void
|
|
{
|
|
if (! config('livewire-material.mail.components')) {
|
|
return;
|
|
}
|
|
|
|
$paths = (array) config('mail.markdown.paths', []);
|
|
|
|
if (! in_array(static::mailComponentPath(), $paths, true)) {
|
|
config(['mail.markdown.paths' => [...$paths, static::mailComponentPath()]]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register the components as anonymous Blade components under the configured prefix, or
|
|
* under `livewire-material` without one.
|
|
*
|
|
* A compiled `<x-button>` names the view namespace Blade derives from the prefix, or from the
|
|
* component folder's absolute path when there is none. That path differs between a laptop and
|
|
* a container sharing `storage/framework/views`, or between release directories, while the
|
|
* compiled file's name does not — so a view compiled on one showed `a1b2…::button` as text on
|
|
* the other. A prefix does not stop an unprefixed tag resolving. The path's namespace stays
|
|
* registered, so views compiled before this release still render until they are recompiled.
|
|
*
|
|
* The package's own views never go through this registration: they write
|
|
* `<x-livewire-material::button>`, which resolves through the view namespace whatever the
|
|
* prefix, and which an application's own `<x-button>` cannot shadow.
|
|
*/
|
|
protected function registerComponents(): void
|
|
{
|
|
Blade::anonymousComponentPath(
|
|
static::componentPath(),
|
|
filled(config('livewire-material.prefix')) ? config('livewire-material.prefix') : 'livewire-material',
|
|
);
|
|
|
|
View::addNamespace(hash('xxh128', static::componentPath()), static::componentPath());
|
|
}
|
|
|
|
/**
|
|
* Put the M3 paginators in front of Laravel's and Livewire's own. Prepended to their
|
|
* namespaces rather than set as the default view, because Livewire sets its own default on
|
|
* every render; an application's published `vendor/pagination` or `vendor/livewire` views are
|
|
* looked up before any namespace path, so they still win.
|
|
*/
|
|
protected function registerPagination(): void
|
|
{
|
|
if (! config('livewire-material.pagination')) {
|
|
return;
|
|
}
|
|
|
|
$this->callAfterResolving('view', function (Factory $view): void {
|
|
$view->prependNamespace('pagination', __DIR__.'/../resources/views/pagination/laravel');
|
|
$view->prependNamespace('livewire', __DIR__.'/../resources/views/pagination/livewire');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* blade-icons registers a class-based <x-icon> of its own, and Blade resolves a
|
|
* registered class alias before any anonymous component path, so ours would never
|
|
* render. It reads the key in its boot(); a booting callback runs after every
|
|
* register() — so after blade-icons merges its defaults over the key — and before
|
|
* any provider boots.
|
|
*/
|
|
protected function disableBladeIconsComponent(): void
|
|
{
|
|
$this->app->booting(function (): void {
|
|
config(['blade-icons.components.default' => null]);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Mount the showcase when it is enabled.
|
|
*/
|
|
protected function registerShowcase(): void
|
|
{
|
|
// Registered even with the showcase off: `php artisan view:cache` compiles every view in the
|
|
// package's namespace, the showcase's pages included, and <x-showcase::…> must resolve there.
|
|
Blade::anonymousComponentPath(__DIR__.'/../resources/views/showcase/components', 'showcase');
|
|
|
|
if (! config('livewire-material.showcase.enabled')) {
|
|
return;
|
|
}
|
|
|
|
if ($this->app->routesAreCached()) {
|
|
return;
|
|
}
|
|
|
|
Route::middleware(config('livewire-material.showcase.middleware'))
|
|
->prefix(config('livewire-material.showcase.path'))
|
|
->name('livewire-material.')
|
|
->group(__DIR__.'/../routes/showcase.php');
|
|
}
|
|
}
|