From c3147eab288144d67c1de2fc3609df3546ff20a9 Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Sat, 10 Dec 2022 00:44:49 +0200 Subject: [PATCH 01/10] Vite multiple configuration support --- src/Illuminate/Contracts/Foundation/Vite.php | 150 +++++++++ .../Providers/FoundationServiceProvider.php | 11 +- .../Providers/ViteServiceProvider.php | 33 ++ src/Illuminate/Foundation/Vite.php | 41 ++- src/Illuminate/Foundation/ViteManager.php | 286 ++++++++++++++++++ src/Illuminate/Support/Facades/Vite.php | 27 +- .../Compilers/Concerns/CompilesHelpers.php | 19 +- 7 files changed, 538 insertions(+), 29 deletions(-) create mode 100644 src/Illuminate/Contracts/Foundation/Vite.php create mode 100644 src/Illuminate/Foundation/Providers/ViteServiceProvider.php create mode 100644 src/Illuminate/Foundation/ViteManager.php diff --git a/src/Illuminate/Contracts/Foundation/Vite.php b/src/Illuminate/Contracts/Foundation/Vite.php new file mode 100644 index 000000000000..7cfa3fcb1521 --- /dev/null +++ b/src/Illuminate/Contracts/Foundation/Vite.php @@ -0,0 +1,150 @@ + Vite::class, + ViteServiceProvider::class, ]; /** diff --git a/src/Illuminate/Foundation/Providers/ViteServiceProvider.php b/src/Illuminate/Foundation/Providers/ViteServiceProvider.php new file mode 100644 index 000000000000..a1df4d7dd4ff --- /dev/null +++ b/src/Illuminate/Foundation/Providers/ViteServiceProvider.php @@ -0,0 +1,33 @@ +app->singleton('vite', fn ($app) => new ViteManager($app)); + $this->app->singleton('vite.app', fn ($app) => $app['vite']->app()); + $this->app->bind(Vite::class, 'vite.app'); + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return ['vite', 'vite.app', Vite::class]; + } +} diff --git a/src/Illuminate/Foundation/Vite.php b/src/Illuminate/Foundation/Vite.php index 0eddc517b2b5..dfc94f6b2226 100644 --- a/src/Illuminate/Foundation/Vite.php +++ b/src/Illuminate/Foundation/Vite.php @@ -3,13 +3,16 @@ namespace Illuminate\Foundation; use Exception; -use Illuminate\Contracts\Support\Htmlable; +use Illuminate\Contracts\Foundation\Vite as ViteContract; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\HtmlString; use Illuminate\Support\Str; use Illuminate\Support\Traits\Macroable; +use ReflectionClass; +use ReflectionMethod; -class Vite implements Htmlable +class Vite implements ViteContract { use Macroable; @@ -90,6 +93,38 @@ class Vite implements Htmlable */ protected static $manifests = []; + /** + * Apply configuration to the Vite instance. + * + * @param array $config + * @return $this + */ + public function configure($config) + { + $class = new ReflectionClass($this); + $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC); + $currentMethod = __FUNCTION__; + + $methodKeyMap = [ + 'useCspNonce' => 'nonce', + 'useScriptTagAttributes' => 'tag_attributes.script', + 'useStyleTagAttributes' => 'tag_attributes.style', + 'usePreloadTagAttributes' => 'tag_attributes.preload', + ]; + + collect($methods)->filter(fn (ReflectionMethod $method) => + ! $method->isStatic() + && $method->getName() !== $currentMethod + && preg_match('/^(use|with)/', $method->getName()) + )->each(function (ReflectionMethod $method) use ($config, $methodKeyMap) { + $key = $methodKeyMap[$method->getName()] + ?? str($method->getName())->after('use')->after('with')->snake()->value(); + Arr::has($config, $key) && $method->invoke($this, Arr::get($config, $key)); + }); + + return $this; + } + /** * Get the preloaded assets. * @@ -113,7 +148,7 @@ public function cspNonce() /** * Generate or set a Content Security Policy nonce to apply to all generated tags. * - * @param ?string $nonce + * @param string|null $nonce * @return string */ public function useCspNonce($nonce = null) diff --git a/src/Illuminate/Foundation/ViteManager.php b/src/Illuminate/Foundation/ViteManager.php new file mode 100644 index 000000000000..1907cb9c5c66 --- /dev/null +++ b/src/Illuminate/Foundation/ViteManager.php @@ -0,0 +1,286 @@ +config->get('vite.app', 'default'); + } + + /** + * Create a new driver instance. + * + * @param string $driver + * @return ViteContract + */ + protected function createDriver($driver) + { + try { + return parent::createDriver($driver); + } catch (InvalidArgumentException) { + return $this->createApp($driver); + } + } + + /** + * Create a new app instance. + * + * @param string $app + * @return ViteContract + */ + protected function createApp($app) + { + return ($this->appFactory ?? function (string $app, ViteContract $vite, array $config) { + return $vite->configure($config); + })($app, new Vite, config("vite.apps.$app", []), $this->container); + } + + /** + * Register an app factory callback. + * + * @param callable(string, ViteContract, array, Container): ViteContract $appFactory + * @return void + */ + public function useAppFactory($appFactory) + { + $this->appFactory = $appFactory; + } + + /** + * Get an app instance. + * + * @param string|null $app + * @return ViteContract + * + * @throws \InvalidArgumentException + */ + public function app($app = null) + { + return $this->driver($app); + } + + /** + * Apply configuration to the Vite instance. + * + * @param array $config + * @return ViteContract + */ + public function configure($config) + { + return $this->app()->configure($config); + } + + /** + * Get the preloaded assets. + * + * @return array + */ + public function preloadedAssets() + { + return $this->app()->preloadedAssets(); + } + + /** + * Get the Content Security Policy nonce applied to all generated tags. + * + * @return string|null + */ + public function cspNonce() + { + return $this->app()->cspNonce(); + } + + /** + * Generate or set a Content Security Policy nonce to apply to all generated tags. + * + * @param string|null $nonce + * @return string + */ + public function useCspNonce($nonce = null) + { + return $this->app()->useCspNonce($nonce); + } + + /** + * Use the given key to detect integrity hashes in the manifest. + * + * @param string|false $key + * @return ViteContract + */ + public function useIntegrityKey($key) + { + return $this->app()->useIntegrityKey($key); + } + + /** + * Set the Vite entry points. + * + * @param array $entryPoints + * @return ViteContract + */ + public function withEntryPoints($entryPoints) + { + return $this->app()->withEntryPoints($entryPoints); + } + + /** + * Set the filename for the manifest file. + * + * @param string $filename + * @return ViteContract + */ + public function useManifestFilename($filename) + { + return $this->app()->useManifestFilename($filename); + } + + /** + * Get the Vite "hot" file path. + * + * @return string + */ + public function hotFile(): string + { + return $this->app()->hotFile(); + } + + /** + * Set the Vite "hot" file path. + * + * @param string $path + * @return ViteContract + */ + public function useHotFile($path) + { + return $this->app()->useHotFile($path); + } + + /** + * Set the Vite build directory. + * + * @param string $path + * @return ViteContract + */ + public function useBuildDirectory($path) + { + return $this->app()->useBuildDirectory($path); + } + + /** + * Use the given callback to resolve attributes for script tags. + * + * @param (callable(string, string, ?array, ?array): array)|array $attributes + * @return ViteContract + */ + public function useScriptTagAttributes($attributes) + { + return $this->app()->useScriptTagAttributes($attributes); + } + + /** + * Use the given callback to resolve attributes for style tags. + * + * @param (callable(string, string, ?array, ?array): array)|array $attributes + * @return ViteContract + */ + public function useStyleTagAttributes($attributes) + { + return $this->app()->useStyleTagAttributes($attributes); + } + + /** + * Use the given callback to resolve attributes for preload tags. + * + * @param (callable(string, string, ?array, ?array): array)|array $attributes + * @return ViteContract + */ + public function usePreloadTagAttributes($attributes) + { + return $this->app()->usePreloadTagAttributes($attributes); + } + + /** + * Generate Vite tags for an entrypoint. + * + * @param string|string[] $entrypoints + * @param string|null $buildDirectory + * @return \Illuminate\Support\HtmlString + * + * @throws \Exception + */ + public function __invoke($entrypoints, $buildDirectory = null) + { + return $this->app()->__invoke($entrypoints, $buildDirectory); + } + + /** + * Generate React refresh runtime script. + * + * @return \Illuminate\Support\HtmlString|void + */ + public function reactRefresh() + { + return $this->app()->reactRefresh(); + } + + /** + * Get the URL for an asset. + * + * @param string $asset + * @param string|null $buildDirectory + * @return string + */ + public function asset($asset, $buildDirectory = null) + { + return $this->app()->asset($asset, $buildDirectory); + } + + /** + * Get a unique hash representing the current manifest, or null if there is no manifest. + * + * @return string|null + */ + public function manifestHash($buildDirectory = null) + { + return $this->app()->manifestHash($buildDirectory); + } + + /** + * Determine if the HMR server is running. + * + * @return bool + */ + public function isRunningHot() + { + return $this->app()->isRunningHot(); + } + + /** + * Get the Vite tag content as a string of HTML. + * + * @return string + */ + public function toHtml() + { + return $this->app()->toHtml(); + } +} diff --git a/src/Illuminate/Support/Facades/Vite.php b/src/Illuminate/Support/Facades/Vite.php index ad5576463699..4e554d132385 100644 --- a/src/Illuminate/Support/Facades/Vite.php +++ b/src/Illuminate/Support/Facades/Vite.php @@ -2,19 +2,24 @@ namespace Illuminate\Support\Facades; +use Illuminate\Contracts\Foundation\Vite as ViteContract; + /** + * @method static void useAppFactory((callable(string, ViteContract, array, Container): ViteContract) $appResolver) + * @method static ViteContract app(string|null $app = null) + * @method static ViteContract configure(array $config) * @method static array preloadedAssets() * @method static string|null cspNonce() - * @method static string useCspNonce(?string $nonce = null) - * @method static \Illuminate\Foundation\Vite useIntegrityKey(string|false $key) - * @method static \Illuminate\Foundation\Vite withEntryPoints(array $entryPoints) - * @method static \Illuminate\Foundation\Vite useManifestFilename(string $filename) + * @method static string useCspNonce(string|null $nonce = null) + * @method static ViteContract useIntegrityKey(string|false $key) + * @method static ViteContract withEntryPoints(array $entryPoints) + * @method static ViteContract useManifestFilename(string $filename) * @method static string hotFile() - * @method static \Illuminate\Foundation\Vite useHotFile(string $path) - * @method static \Illuminate\Foundation\Vite useBuildDirectory(string $path) - * @method static \Illuminate\Foundation\Vite useScriptTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) - * @method static \Illuminate\Foundation\Vite useStyleTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) - * @method static \Illuminate\Foundation\Vite usePreloadTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) + * @method static ViteContract useHotFile(string $path) + * @method static ViteContract useBuildDirectory(string $path) + * @method static ViteContract useScriptTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) + * @method static ViteContract useStyleTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) + * @method static ViteContract usePreloadTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) * @method static \Illuminate\Support\HtmlString|void reactRefresh() * @method static string asset(string $asset, string|null $buildDirectory = null) * @method static string|null manifestHash(string|null $buildDirectory = null) @@ -25,7 +30,7 @@ * @method static bool hasMacro(string $name) * @method static void flushMacros() * - * @see \Illuminate\Foundation\Vite + * @see \Illuminate\Foundation\ViteManager */ class Vite extends Facade { @@ -36,6 +41,6 @@ class Vite extends Facade */ protected static function getFacadeAccessor() { - return \Illuminate\Foundation\Vite::class; + return 'vite'; } } diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesHelpers.php b/src/Illuminate/View/Compilers/Concerns/CompilesHelpers.php index 6c6fcd996830..d43fcead1367 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesHelpers.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesHelpers.php @@ -59,9 +59,20 @@ protected function compileVite($arguments) { $arguments ??= '()'; - $class = Vite::class; + return ""; + } + + /** + * Compile the "viteApp" statements into valid PHP. + * + * @param ?string $arguments + * @return string + */ + protected function compileViteApp($arguments) + { + $arguments ??= '()'; - return ""; + return "app{$arguments}->toHtml(); ?>"; } /** @@ -71,8 +82,6 @@ protected function compileVite($arguments) */ protected function compileViteReactRefresh() { - $class = Vite::class; - - return "reactRefresh(); ?>"; + return "reactRefresh(); ?>"; } } From 59a99f6a54ac9fadd783ba73c9e6308f2ceef034 Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Sat, 10 Dec 2022 11:47:14 +0200 Subject: [PATCH 02/10] fix tests --- src/Illuminate/Foundation/Providers/ViteServiceProvider.php | 6 ++++-- tests/Http/Middleware/VitePreloadingTest.php | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Providers/ViteServiceProvider.php b/src/Illuminate/Foundation/Providers/ViteServiceProvider.php index a1df4d7dd4ff..a47957fad6ae 100644 --- a/src/Illuminate/Foundation/Providers/ViteServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ViteServiceProvider.php @@ -2,8 +2,9 @@ namespace Illuminate\Foundation\Providers; -use Illuminate\Contracts\Foundation\Vite; +use Illuminate\Contracts\Foundation\Vite as ViteContract; use Illuminate\Contracts\Support\DeferrableProvider; +use Illuminate\Foundation\Vite; use Illuminate\Foundation\ViteManager; use Illuminate\Support\ServiceProvider; @@ -18,6 +19,7 @@ public function register() { $this->app->singleton('vite', fn ($app) => new ViteManager($app)); $this->app->singleton('vite.app', fn ($app) => $app['vite']->app()); + $this->app->bind(ViteContract::class, 'vite.app'); $this->app->bind(Vite::class, 'vite.app'); } @@ -28,6 +30,6 @@ public function register() */ public function provides() { - return ['vite', 'vite.app', Vite::class]; + return ['vite', 'vite.app', ViteContract::class, Vite::class]; } } diff --git a/tests/Http/Middleware/VitePreloadingTest.php b/tests/Http/Middleware/VitePreloadingTest.php index 641280cc8d9e..a55f07dce7e1 100644 --- a/tests/Http/Middleware/VitePreloadingTest.php +++ b/tests/Http/Middleware/VitePreloadingTest.php @@ -21,7 +21,7 @@ protected function tearDown(): void public function testItDoesNotSetLinkTagWhenNoTagsHaveBeenPreloaded() { $app = new Container(); - $app->instance(Vite::class, new class extends Vite + $app->instance('vite', new class extends Vite { protected $preloadedAssets = []; }); @@ -37,7 +37,7 @@ public function testItDoesNotSetLinkTagWhenNoTagsHaveBeenPreloaded() public function testItAddsPreloadLinkHeader() { $app = new Container(); - $app->instance(Vite::class, new class extends Vite + $app->instance('vite', new class extends Vite { protected $preloadedAssets = [ 'https://laravel.com/app.js' => [ From 4509b8dc2d45ff65fe6963b8ffbf3e8b4267cd2a Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Sat, 10 Dec 2022 14:43:03 +0200 Subject: [PATCH 03/10] fix tests --- tests/View/Blade/BladeHelpersTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/View/Blade/BladeHelpersTest.php b/tests/View/Blade/BladeHelpersTest.php index 8e071c38b6c6..83f4035a9ccc 100644 --- a/tests/View/Blade/BladeHelpersTest.php +++ b/tests/View/Blade/BladeHelpersTest.php @@ -11,10 +11,10 @@ public function testEchosAreCompiled() $this->assertSame('', $this->compiler->compileString('@dd($var1)')); $this->assertSame('', $this->compiler->compileString('@dd($var1, $var2)')); $this->assertSame('', $this->compiler->compileString('@dump($var1, $var2)')); - $this->assertSame('', $this->compiler->compileString('@vite')); - $this->assertSame('', $this->compiler->compileString('@vite()')); - $this->assertSame('', $this->compiler->compileString('@vite(\'resources/js/app.js\')')); - $this->assertSame('', $this->compiler->compileString('@vite([\'resources/js/app.js\'])')); - $this->assertSame('reactRefresh(); ?>', $this->compiler->compileString('@viteReactRefresh')); + $this->assertSame('', $this->compiler->compileString('@vite')); + $this->assertSame('', $this->compiler->compileString('@vite()')); + $this->assertSame('', $this->compiler->compileString('@vite(\'resources/js/app.js\')')); + $this->assertSame('', $this->compiler->compileString('@vite([\'resources/js/app.js\'])')); + $this->assertSame('reactRefresh(); ?>', $this->compiler->compileString('@viteReactRefresh')); } } From 57458401e38998ff43e0d316faf9c9d93d6b4f93 Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Sat, 10 Dec 2022 14:49:44 +0200 Subject: [PATCH 04/10] fix Vite facade --- src/Illuminate/Foundation/ViteManager.php | 4 +++- src/Illuminate/Support/Facades/Vite.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/ViteManager.php b/src/Illuminate/Foundation/ViteManager.php index 1907cb9c5c66..126b12a5c05d 100644 --- a/src/Illuminate/Foundation/ViteManager.php +++ b/src/Illuminate/Foundation/ViteManager.php @@ -58,11 +58,13 @@ protected function createApp($app) * Register an app factory callback. * * @param callable(string, ViteContract, array, Container): ViteContract $appFactory - * @return void + * @return $this */ public function useAppFactory($appFactory) { $this->appFactory = $appFactory; + + return $this; } /** diff --git a/src/Illuminate/Support/Facades/Vite.php b/src/Illuminate/Support/Facades/Vite.php index 4e554d132385..bab0a1008138 100644 --- a/src/Illuminate/Support/Facades/Vite.php +++ b/src/Illuminate/Support/Facades/Vite.php @@ -5,7 +5,7 @@ use Illuminate\Contracts\Foundation\Vite as ViteContract; /** - * @method static void useAppFactory((callable(string, ViteContract, array, Container): ViteContract) $appResolver) + * @method static \Illuminate\Foundation\ViteManager useAppFactory(callable(string, ViteContract, array, Container): ViteContract $appFactory) * @method static ViteContract app(string|null $app = null) * @method static ViteContract configure(array $config) * @method static array preloadedAssets() From 7bf806620658991f05991ee6ad140d64914cef6b Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Sat, 10 Dec 2022 15:04:24 +0200 Subject: [PATCH 05/10] fix Vite facade again --- src/Illuminate/Support/Facades/Vite.php | 37 +++++++++++++------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Illuminate/Support/Facades/Vite.php b/src/Illuminate/Support/Facades/Vite.php index bab0a1008138..bc68ef07f979 100644 --- a/src/Illuminate/Support/Facades/Vite.php +++ b/src/Illuminate/Support/Facades/Vite.php @@ -2,33 +2,34 @@ namespace Illuminate\Support\Facades; -use Illuminate\Contracts\Foundation\Vite as ViteContract; - /** - * @method static \Illuminate\Foundation\ViteManager useAppFactory(callable(string, ViteContract, array, Container): ViteContract $appFactory) - * @method static ViteContract app(string|null $app = null) - * @method static ViteContract configure(array $config) + * @method static string getDefaultDriver() + * @method static \Illuminate\Foundation\ViteManager useAppFactory(callable(string, \Illuminate\Contracts\Foundation\Vite, array, \Illuminate\Contracts\Container\Container): \Illuminate\Contracts\Foundation\Vite $appFactory) + * @method static \Illuminate\Contracts\Foundation\Vite app(string|null $app = null) + * @method static \Illuminate\Contracts\Foundation\Vite configure(array $config) * @method static array preloadedAssets() * @method static string|null cspNonce() * @method static string useCspNonce(string|null $nonce = null) - * @method static ViteContract useIntegrityKey(string|false $key) - * @method static ViteContract withEntryPoints(array $entryPoints) - * @method static ViteContract useManifestFilename(string $filename) + * @method static \Illuminate\Contracts\Foundation\Vite useIntegrityKey(string|false $key) + * @method static \Illuminate\Contracts\Foundation\Vite withEntryPoints(array $entryPoints) + * @method static \Illuminate\Contracts\Foundation\Vite useManifestFilename(string $filename) * @method static string hotFile() - * @method static ViteContract useHotFile(string $path) - * @method static ViteContract useBuildDirectory(string $path) - * @method static ViteContract useScriptTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) - * @method static ViteContract useStyleTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) - * @method static ViteContract usePreloadTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) + * @method static \Illuminate\Contracts\Foundation\Vite useHotFile(string $path) + * @method static \Illuminate\Contracts\Foundation\Vite useBuildDirectory(string $path) + * @method static \Illuminate\Contracts\Foundation\Vite useScriptTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) + * @method static \Illuminate\Contracts\Foundation\Vite useStyleTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) + * @method static \Illuminate\Contracts\Foundation\Vite usePreloadTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) * @method static \Illuminate\Support\HtmlString|void reactRefresh() * @method static string asset(string $asset, string|null $buildDirectory = null) - * @method static string|null manifestHash(string|null $buildDirectory = null) + * @method static string|null manifestHash(void $buildDirectory = null) * @method static bool isRunningHot() * @method static string toHtml() - * @method static void macro(string $name, object|callable $macro) - * @method static void mixin(object $mixin, bool $replace = true) - * @method static bool hasMacro(string $name) - * @method static void flushMacros() + * @method static mixed driver(string|null $driver = null) + * @method static \Illuminate\Foundation\ViteManager extend(string $driver, \Closure $callback) + * @method static array getDrivers() + * @method static \Illuminate\Contracts\Container\Container getContainer() + * @method static \Illuminate\Foundation\ViteManager setContainer(\Illuminate\Contracts\Container\Container $container) + * @method static \Illuminate\Foundation\ViteManager forgetDrivers() * * @see \Illuminate\Foundation\ViteManager */ From 037af7f8d28aa000957d83389416f54862d0e220 Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Sat, 10 Dec 2022 15:26:55 +0200 Subject: [PATCH 06/10] fix Vite facade again --- src/Illuminate/Contracts/Foundation/Vite.php | 1 + src/Illuminate/Foundation/ViteManager.php | 34 ++++++++++---------- src/Illuminate/Support/Facades/Vite.php | 4 +-- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/Illuminate/Contracts/Foundation/Vite.php b/src/Illuminate/Contracts/Foundation/Vite.php index 7cfa3fcb1521..c0f1ed0bdbd8 100644 --- a/src/Illuminate/Contracts/Foundation/Vite.php +++ b/src/Illuminate/Contracts/Foundation/Vite.php @@ -137,6 +137,7 @@ public function asset($asset, $buildDirectory = null); /** * Get a unique hash representing the current manifest, or null if there is no manifest. * + * @param string|null $buildDirectory * @return string|null */ public function manifestHash($buildDirectory = null); diff --git a/src/Illuminate/Foundation/ViteManager.php b/src/Illuminate/Foundation/ViteManager.php index 126b12a5c05d..85c977de51f6 100644 --- a/src/Illuminate/Foundation/ViteManager.php +++ b/src/Illuminate/Foundation/ViteManager.php @@ -3,7 +3,6 @@ namespace Illuminate\Foundation; use Illuminate\Contracts\Foundation\Vite as ViteContract; -use Illuminate\Contracts\Container\Container; use Illuminate\Support\Manager; use InvalidArgumentException; @@ -12,7 +11,7 @@ class ViteManager extends Manager implements ViteContract /** * The registered app factory. * - * @var (callable(string, ViteContract, array, Container): ViteContract)|null + * @var (callable(\Illuminate\Contracts\Foundation\Vite, string, array, \Illuminate\Contracts\Container\Container): \Illuminate\Contracts\Foundation\Vite)|null */ protected $appFactory = null; @@ -30,7 +29,7 @@ public function getDefaultDriver() * Create a new driver instance. * * @param string $driver - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ protected function createDriver($driver) { @@ -45,19 +44,19 @@ protected function createDriver($driver) * Create a new app instance. * * @param string $app - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ protected function createApp($app) { - return ($this->appFactory ?? function (string $app, ViteContract $vite, array $config) { + return ($this->appFactory ?? function (ViteContract $vite, string $app, array $config) { return $vite->configure($config); - })($app, new Vite, config("vite.apps.$app", []), $this->container); + })(new Vite, $app, config("vite.apps.$app", []), $this->container); } /** * Register an app factory callback. * - * @param callable(string, ViteContract, array, Container): ViteContract $appFactory + * @param callable(\Illuminate\Contracts\Foundation\Vite, string, array, \Illuminate\Contracts\Container\Container): \Illuminate\Contracts\Foundation\Vite $appFactory * @return $this */ public function useAppFactory($appFactory) @@ -71,7 +70,7 @@ public function useAppFactory($appFactory) * Get an app instance. * * @param string|null $app - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite * * @throws \InvalidArgumentException */ @@ -84,7 +83,7 @@ public function app($app = null) * Apply configuration to the Vite instance. * * @param array $config - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ public function configure($config) { @@ -126,7 +125,7 @@ public function useCspNonce($nonce = null) * Use the given key to detect integrity hashes in the manifest. * * @param string|false $key - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ public function useIntegrityKey($key) { @@ -137,7 +136,7 @@ public function useIntegrityKey($key) * Set the Vite entry points. * * @param array $entryPoints - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ public function withEntryPoints($entryPoints) { @@ -148,7 +147,7 @@ public function withEntryPoints($entryPoints) * Set the filename for the manifest file. * * @param string $filename - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ public function useManifestFilename($filename) { @@ -169,7 +168,7 @@ public function hotFile(): string * Set the Vite "hot" file path. * * @param string $path - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ public function useHotFile($path) { @@ -180,7 +179,7 @@ public function useHotFile($path) * Set the Vite build directory. * * @param string $path - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ public function useBuildDirectory($path) { @@ -191,7 +190,7 @@ public function useBuildDirectory($path) * Use the given callback to resolve attributes for script tags. * * @param (callable(string, string, ?array, ?array): array)|array $attributes - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ public function useScriptTagAttributes($attributes) { @@ -202,7 +201,7 @@ public function useScriptTagAttributes($attributes) * Use the given callback to resolve attributes for style tags. * * @param (callable(string, string, ?array, ?array): array)|array $attributes - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ public function useStyleTagAttributes($attributes) { @@ -213,7 +212,7 @@ public function useStyleTagAttributes($attributes) * Use the given callback to resolve attributes for preload tags. * * @param (callable(string, string, ?array, ?array): array)|array $attributes - * @return ViteContract + * @return \Illuminate\Contracts\Foundation\Vite */ public function usePreloadTagAttributes($attributes) { @@ -259,6 +258,7 @@ public function asset($asset, $buildDirectory = null) /** * Get a unique hash representing the current manifest, or null if there is no manifest. * + * @param string|null $buildDirectory * @return string|null */ public function manifestHash($buildDirectory = null) diff --git a/src/Illuminate/Support/Facades/Vite.php b/src/Illuminate/Support/Facades/Vite.php index bc68ef07f979..99e27ce270ac 100644 --- a/src/Illuminate/Support/Facades/Vite.php +++ b/src/Illuminate/Support/Facades/Vite.php @@ -4,7 +4,7 @@ /** * @method static string getDefaultDriver() - * @method static \Illuminate\Foundation\ViteManager useAppFactory(callable(string, \Illuminate\Contracts\Foundation\Vite, array, \Illuminate\Contracts\Container\Container): \Illuminate\Contracts\Foundation\Vite $appFactory) + * @method static \Illuminate\Foundation\ViteManager useAppFactory(callable(\Illuminate\Contracts\Foundation\Vite, string, array, \Illuminate\Contracts\Container\Container): \Illuminate\Contracts\Foundation\Vite $appFactory) * @method static \Illuminate\Contracts\Foundation\Vite app(string|null $app = null) * @method static \Illuminate\Contracts\Foundation\Vite configure(array $config) * @method static array preloadedAssets() @@ -21,7 +21,7 @@ * @method static \Illuminate\Contracts\Foundation\Vite usePreloadTagAttributes((callable(string, string, ?array, ?array): array)|array $attributes) * @method static \Illuminate\Support\HtmlString|void reactRefresh() * @method static string asset(string $asset, string|null $buildDirectory = null) - * @method static string|null manifestHash(void $buildDirectory = null) + * @method static string|null manifestHash(string|null $buildDirectory = null) * @method static bool isRunningHot() * @method static string toHtml() * @method static mixed driver(string|null $driver = null) From a43c481b7dfe64fee0d0807d86349232ea5efd03 Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Sat, 10 Dec 2022 15:45:35 +0200 Subject: [PATCH 07/10] Assertions for @viteApp directive --- tests/View/Blade/BladeHelpersTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/View/Blade/BladeHelpersTest.php b/tests/View/Blade/BladeHelpersTest.php index 83f4035a9ccc..11c1c6089a9a 100644 --- a/tests/View/Blade/BladeHelpersTest.php +++ b/tests/View/Blade/BladeHelpersTest.php @@ -15,6 +15,9 @@ public function testEchosAreCompiled() $this->assertSame('', $this->compiler->compileString('@vite()')); $this->assertSame('', $this->compiler->compileString('@vite(\'resources/js/app.js\')')); $this->assertSame('', $this->compiler->compileString('@vite([\'resources/js/app.js\'])')); + $this->assertSame('app()->toHtml(); ?>', $this->compiler->compileString('@viteApp')); + $this->assertSame('app()->toHtml(); ?>', $this->compiler->compileString('@viteApp()')); + $this->assertSame('app(\'app\')->toHtml(); ?>', $this->compiler->compileString('@viteApp(\'app\')')); $this->assertSame('reactRefresh(); ?>', $this->compiler->compileString('@viteReactRefresh')); } } From d74ce1ff88ce9d37a53199434fc0cb4626a41617 Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Mon, 12 Dec 2022 11:51:21 +0200 Subject: [PATCH 08/10] Vite configure with array test --- tests/Foundation/FoundationViteTest.php | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/Foundation/FoundationViteTest.php b/tests/Foundation/FoundationViteTest.php index 68814a7535b1..91bc2ea27388 100644 --- a/tests/Foundation/FoundationViteTest.php +++ b/tests/Foundation/FoundationViteTest.php @@ -7,6 +7,7 @@ use Illuminate\Support\Facades\Vite as ViteFacade; use Illuminate\Support\Str; use Orchestra\Testbench\TestCase; +use ReflectionObject; class FoundationViteTest extends TestCase { @@ -982,6 +983,43 @@ public function testItCanConfigureTheManifestFilename() rmdir(public_path($buildDir)); } + public function testItCanBeConfiguredWithArray() + { + $config = [ + 'nonce' => 'expected-nonce', + 'integrity_key' => 'some-integrity-key', + 'entry_points' => ['resources/js/app.js'], + 'hot_file' => 'cold', + 'build_directory' => 'build/packages', + 'manifest_filename' => 'oktoberfest.json', + 'tag_attributes' => [ + 'script' => ['type' => 'text/javascript', 'nomodule'], + 'style' => ['type' => 'text/css'], + 'preload' => ['rel' => 'dummy'], + ], + ]; + + $vite = app(Vite::class)->configure($config); + + $integrityKey = (new ReflectionObject($vite))->getProperty('integrityKey')->getValue($vite); + $entryPoints = (new ReflectionObject($vite))->getProperty('entryPoints')->getValue($vite); + $buildDirectory = (new ReflectionObject($vite))->getProperty('buildDirectory')->getValue($vite); + $manifestFilename = (new ReflectionObject($vite))->getProperty('manifestFilename')->getValue($vite); + $scriptTagAttributesResolvers = (new ReflectionObject($vite))->getProperty('scriptTagAttributesResolvers')->getValue($vite); + $styleTagAttributesResolvers = (new ReflectionObject($vite))->getProperty('styleTagAttributesResolvers')->getValue($vite); + $preloadTagAttributesResolvers = (new ReflectionObject($vite))->getProperty('preloadTagAttributesResolvers')->getValue($vite); + + $this->assertEquals($vite->cspNonce(), $config['nonce']); + $this->assertEquals($integrityKey, $config['integrity_key']); + $this->assertEquals($entryPoints, $config['entry_points']); + $this->assertEquals($vite->hotFile(), $config['hot_file']); + $this->assertEquals($buildDirectory, $config['build_directory']); + $this->assertEquals($manifestFilename, $config['manifest_filename']); + $this->assertEquals($scriptTagAttributesResolvers[0](), $config['tag_attributes']['script']); + $this->assertEquals($styleTagAttributesResolvers[0](), $config['tag_attributes']['style']); + $this->assertEquals($preloadTagAttributesResolvers[0](), $config['tag_attributes']['preload']); + } + protected function makeViteManifest($contents = null, $path = 'build') { app()->singleton('path.public', fn () => __DIR__); From e99ca840accaceff1c7f2e8b7a916a147ce1a2f5 Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Mon, 12 Dec 2022 12:13:58 +0200 Subject: [PATCH 09/10] fix test for PHP < 8.1 --- tests/Foundation/FoundationViteTest.php | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/Foundation/FoundationViteTest.php b/tests/Foundation/FoundationViteTest.php index 91bc2ea27388..22ed61374366 100644 --- a/tests/Foundation/FoundationViteTest.php +++ b/tests/Foundation/FoundationViteTest.php @@ -1001,23 +1001,23 @@ public function testItCanBeConfiguredWithArray() $vite = app(Vite::class)->configure($config); - $integrityKey = (new ReflectionObject($vite))->getProperty('integrityKey')->getValue($vite); - $entryPoints = (new ReflectionObject($vite))->getProperty('entryPoints')->getValue($vite); - $buildDirectory = (new ReflectionObject($vite))->getProperty('buildDirectory')->getValue($vite); - $manifestFilename = (new ReflectionObject($vite))->getProperty('manifestFilename')->getValue($vite); - $scriptTagAttributesResolvers = (new ReflectionObject($vite))->getProperty('scriptTagAttributesResolvers')->getValue($vite); - $styleTagAttributesResolvers = (new ReflectionObject($vite))->getProperty('styleTagAttributesResolvers')->getValue($vite); - $preloadTagAttributesResolvers = (new ReflectionObject($vite))->getProperty('preloadTagAttributesResolvers')->getValue($vite); - $this->assertEquals($vite->cspNonce(), $config['nonce']); - $this->assertEquals($integrityKey, $config['integrity_key']); - $this->assertEquals($entryPoints, $config['entry_points']); + $this->assertEquals($this->getViteProperty($vite, 'integrityKey'), $config['integrity_key']); + $this->assertEquals($this->getViteProperty($vite, 'entryPoints'), $config['entry_points']); $this->assertEquals($vite->hotFile(), $config['hot_file']); - $this->assertEquals($buildDirectory, $config['build_directory']); - $this->assertEquals($manifestFilename, $config['manifest_filename']); - $this->assertEquals($scriptTagAttributesResolvers[0](), $config['tag_attributes']['script']); - $this->assertEquals($styleTagAttributesResolvers[0](), $config['tag_attributes']['style']); - $this->assertEquals($preloadTagAttributesResolvers[0](), $config['tag_attributes']['preload']); + $this->assertEquals($this->getViteProperty($vite, 'buildDirectory'), $config['build_directory']); + $this->assertEquals($this->getViteProperty($vite, 'manifestFilename'), $config['manifest_filename']); + $this->assertEquals($this->getViteProperty($vite, 'scriptTagAttributesResolvers')[0](), $config['tag_attributes']['script']); + $this->assertEquals($this->getViteProperty($vite, 'styleTagAttributesResolvers')[0](), $config['tag_attributes']['style']); + $this->assertEquals($this->getViteProperty($vite, 'preloadTagAttributesResolvers')[0](), $config['tag_attributes']['preload']); + } + + protected function getViteProperty($vite, $propertyName) + { + $property = (new ReflectionObject($vite))->getProperty($propertyName); + $property->setAccessible(true); + + return $property->getValue($vite); } protected function makeViteManifest($contents = null, $path = 'build') From caeedc4a39c79a6c6a449f6ba148c066501dd49f Mon Sep 17 00:00:00 2001 From: Sergey Danilchenko Date: Mon, 12 Dec 2022 12:56:22 +0200 Subject: [PATCH 10/10] Vite instantiation test --- src/Illuminate/Foundation/Vite.php | 3 +-- tests/Foundation/FoundationViteTest.php | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Vite.php b/src/Illuminate/Foundation/Vite.php index dfc94f6b2226..8baab5d49031 100644 --- a/src/Illuminate/Foundation/Vite.php +++ b/src/Illuminate/Foundation/Vite.php @@ -112,8 +112,7 @@ public function configure($config) 'usePreloadTagAttributes' => 'tag_attributes.preload', ]; - collect($methods)->filter(fn (ReflectionMethod $method) => - ! $method->isStatic() + collect($methods)->filter(fn (ReflectionMethod $method) => ! $method->isStatic() && $method->getName() !== $currentMethod && preg_match('/^(use|with)/', $method->getName()) )->each(function (ReflectionMethod $method) use ($config, $methodKeyMap) { diff --git a/tests/Foundation/FoundationViteTest.php b/tests/Foundation/FoundationViteTest.php index 22ed61374366..2c2be0be4e33 100644 --- a/tests/Foundation/FoundationViteTest.php +++ b/tests/Foundation/FoundationViteTest.php @@ -983,6 +983,13 @@ public function testItCanConfigureTheManifestFilename() rmdir(public_path($buildDir)); } + public function testItCreatesInstances() + { + $this->assertSame(ViteFacade::app(), ViteFacade::app()); + $this->assertSame(ViteFacade::app('app1'), ViteFacade::app('app1')); + $this->assertNotSame(ViteFacade::app('app2'), ViteFacade::app('app3')); + } + public function testItCanBeConfiguredWithArray() { $config = [