Edit:
I've packaged the solution below into stephancasas/blade-wants-attributes.
I realize this question is old, but in case you or anyone else still needs an answer, I did find a solution. My use case is for package development — building components which universally work with Blade, Livewire, and AlpineJS. In order to do this cleanly, it's imperative that I'm able to evaluate all component attributes within the class constructor.
My solution was to write and register a Blade pre-compiler:
namespace StephanCasas\WireWorkbench\Support;
use Illuminate\View\Compilers\ComponentTagCompiler;
use Illuminate\Support\Str;
class ClassComponentAttributeHydrator extends ComponentTagCompiler
{
public function compile(string $value)
{
$glue = '##BEGIN-COMPONENT-CLASS##';
return collect(
preg_split('/' . $glue . '/s', $value)
)->transform(function ($instance) use ($glue) {
$attrs = [];
preg_match(
'/' . preg_quote('<?php $component->withAttributes(') . '.*/',
$instance,
$attrs
);
if (!count($attrs)) return $instance;
$attrs = (string)Str::of($attrs[0])->after('(')->beforeLast(')');
return "<?php \$__env->share('__attributes', $attrs); ?>\n$glue$instance";
})->join('');
}
}
Then, in my package service provider's boot() method, I can register the pre-compiler:
if (method_exists($this->app['blade.compiler'], 'precompiler')) {
$this->app['blade.compiler']->precompiler(function ($string) {
return app(ClassComponentAttributeHydrator::class)
->compile($string);
});
}
Now, from within the class component, I can assign or access the attributes as needed:
public function __construct() {
$this->attributes = $this->newAttributeBag(
app('view')->shared('__attributes')
);
if ($this->attributes->has('wire:model')) {
// ... do something
}
}
In order to understand how this works, you'll need to take a look at the way Blade pre-compilers work, and how that relates to the structure of cached view output. It will also be helpful to study the lifecycle of View\Factory.
If a problem emerges with this solution, I'll update my remarks.
Cheers.