diff --git a/src/Illuminate/Foundation/Vite.php b/src/Illuminate/Foundation/Vite.php
index 7a137e10db8a..98a016496492 100644
--- a/src/Illuminate/Foundation/Vite.php
+++ b/src/Illuminate/Foundation/Vite.php
@@ -3,11 +3,12 @@
namespace Illuminate\Foundation;
use Exception;
+use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\Collection;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Str;
-class Vite
+class Vite implements Htmlable
{
/**
* The Content Security Policy nonce to apply to all generated tags.
@@ -23,6 +24,27 @@ class Vite
*/
protected $integrityKey = 'integrity';
+ /**
+ * The configured entry points.
+ *
+ * @var array
+ */
+ protected $entryPoints = [];
+
+ /**
+ * The path to the "hot" file.
+ *
+ * @var string|null
+ */
+ protected $hotFile;
+
+ /**
+ * The path to the build directory.
+ *
+ * @var string
+ */
+ protected $buildDirectory = 'build';
+
/**
* The script tag attributes resolvers.
*
@@ -78,6 +100,55 @@ public function useIntegrityKey($key)
return $this;
}
+ /**
+ * Set the Vite entry points.
+ *
+ * @param array $entryPoints
+ * @return $this
+ */
+ public function withEntryPoints($entryPoints)
+ {
+ $this->entryPoints = $entryPoints;
+
+ return $this;
+ }
+
+ /**
+ * Get the Vite "hot" file path.
+ *
+ * @return string
+ */
+ protected function hotFile()
+ {
+ return $this->hotFile ?? public_path('/hot');
+ }
+
+ /**
+ * Set the Vite "hot" file path.
+ *
+ * @param string $path
+ * @return $this
+ */
+ public function useHotFile($path)
+ {
+ $this->hotFile = $path;
+
+ return $this;
+ }
+
+ /**
+ * Set the Vite build directory.
+ *
+ * @param string $path
+ * @return $this
+ */
+ public function useBuildDirectory($path)
+ {
+ $this->buildDirectory = $path;
+
+ return $this;
+ }
+
/**
* Use the given callback to resolve attributes for script tags.
*
@@ -116,15 +187,15 @@ public function useStyleTagAttributes($attributes)
* Generate Vite tags for an entrypoint.
*
* @param string|string[] $entrypoints
- * @param string $buildDirectory
+ * @param string|null $buildDirectory
* @return \Illuminate\Support\HtmlString
*
* @throws \Exception
*/
- public function __invoke($entrypoints, $buildDirectory = 'build')
+ public function __invoke($entrypoints, $buildDirectory = null)
{
$entrypoints = collect($entrypoints);
- $buildDirectory = Str::start($buildDirectory, '/');
+ $buildDirectory ??= $this->buildDirectory;
if ($this->isRunningHot()) {
return new HtmlString(
@@ -396,7 +467,7 @@ public function reactRefresh()
*/
protected function hotAsset($asset)
{
- return rtrim(file_get_contents(public_path('/hot'))).'/'.$asset;
+ return rtrim(file_get_contents($this->hotFile())).'/'.$asset;
}
/**
@@ -406,8 +477,10 @@ protected function hotAsset($asset)
* @param string|null $buildDirectory
* @return string
*/
- public function asset($asset, $buildDirectory = 'build')
+ public function asset($asset, $buildDirectory = null)
{
+ $buildDirectory ??= $this->buildDirectory;
+
if ($this->isRunningHot()) {
return $this->hotAsset($asset);
}
@@ -427,7 +500,7 @@ public function asset($asset, $buildDirectory = 'build')
*/
protected function manifest($buildDirectory)
{
- $path = public_path($buildDirectory.'/manifest.json');
+ $path = $this->manifestPath($buildDirectory);
if (! isset(static::$manifests[$path])) {
if (! is_file($path)) {
@@ -440,6 +513,17 @@ protected function manifest($buildDirectory)
return static::$manifests[$path];
}
+ /**
+ * Get the path to the manifest file for the given build directory.
+ *
+ * @param string $buildDirectory
+ * @return string
+ */
+ protected function manifestPath($buildDirectory)
+ {
+ return public_path($buildDirectory.'/manifest.json');
+ }
+
/**
* Get the chunk for the given entry point / asset.
*
@@ -465,6 +549,16 @@ protected function chunk($manifest, $file)
*/
protected function isRunningHot()
{
- return is_file(public_path('/hot'));
+ return is_file($this->hotFile());
+ }
+
+ /**
+ * Get the Vite tag content as a string of HTML.
+ *
+ * @return string
+ */
+ public function toHtml()
+ {
+ return $this->__invoke($this->entryPoints)->toHtml();
}
}
diff --git a/src/Illuminate/Support/Facades/Vite.php b/src/Illuminate/Support/Facades/Vite.php
index 052beee9b1b2..8b3617ccb134 100644
--- a/src/Illuminate/Support/Facades/Vite.php
+++ b/src/Illuminate/Support/Facades/Vite.php
@@ -6,9 +6,12 @@
* @method static string useCspNonce(?string $nonce = null)
* @method static string|null cspNonce()
* @method static string asset(string $asset, string|null $buildDirectory)
+ * @method static \Illuminate\Foundation\Vite useBuildDirectory(string $path)
+ * @method static \Illuminate\Foundation\Vite useHotFile(string $path)
* @method static \Illuminate\Foundation\Vite useIntegrityKey(string|false $key)
* @method static \Illuminate\Foundation\Vite useScriptTagAttributes(callable|array $callback)
* @method static \Illuminate\Foundation\Vite useStyleTagAttributes(callable|array $callback)
+ * @method static \Illuminate\Foundation\Vite withEntryPoints(array $entryPoints)
*
* @see \Illuminate\Foundation\Vite
*/
diff --git a/tests/Foundation/FoundationViteTest.php b/tests/Foundation/FoundationViteTest.php
index 873f22954959..86fd067423ed 100644
--- a/tests/Foundation/FoundationViteTest.php
+++ b/tests/Foundation/FoundationViteTest.php
@@ -192,8 +192,7 @@ public function testItCanInjectIntegrityWhenPresentInManifest()
$result->toHtml()
);
- unlink(public_path("{$buildDir}/manifest.json"));
- rmdir(public_path($buildDir));
+ $this->cleanViteManifest($buildDir);
}
public function testItCanInjectIntegrityWhenPresentInManifestForCss()
@@ -228,8 +227,7 @@ public function testItCanInjectIntegrityWhenPresentInManifestForCss()
$result->toHtml()
);
- unlink(public_path("{$buildDir}/manifest.json"));
- rmdir(public_path($buildDir));
+ $this->cleanViteManifest($buildDir);
}
public function testItCanInjectIntegrityWhenPresentInManifestForImportedCss()
@@ -264,8 +262,7 @@ public function testItCanInjectIntegrityWhenPresentInManifestForImportedCss()
$result->toHtml()
);
- unlink(public_path("{$buildDir}/manifest.json"));
- rmdir(public_path($buildDir));
+ $this->cleanViteManifest($buildDir);
}
public function testItCanSpecifyIntegrityKey()
@@ -291,8 +288,7 @@ public function testItCanSpecifyIntegrityKey()
$result->toHtml()
);
- unlink(public_path("{$buildDir}/manifest.json"));
- rmdir(public_path($buildDir));
+ $this->cleanViteManifest($buildDir);
}
public function testItCanSpecifyArbitraryAttributesForScriptTagsWhenBuilt()
@@ -539,6 +535,55 @@ public function testItThrowsWhenUnableToFindAssetChunkInBuildMode()
ViteFacade::asset('resources/js/missing.js');
}
+ public function testViteCanSetEntryPointsWithFluentBuilder()
+ {
+ $this->makeViteManifest();
+
+ $vite = app(Vite::class);
+
+ $this->assertSame('', $vite->toHtml());
+
+ $vite->withEntryPoints(['resources/js/app.js']);
+
+ $this->assertSame(
+ '',
+ $vite->toHtml()
+ );
+ }
+
+ public function testViteCanOverrideBuildDirectory()
+ {
+ $this->makeViteManifest(null, 'custom-build');
+
+ $vite = app(Vite::class);
+
+ $vite->withEntryPoints(['resources/js/app.js'])->useBuildDirectory('custom-build');
+
+ $this->assertSame(
+ '',
+ $vite->toHtml()
+ );
+
+ $this->cleanViteManifest('custom-build');
+ }
+
+ public function testViteCanOverrideHotFilePath()
+ {
+ $this->makeViteHotFile('cold');
+
+ $vite = app(Vite::class);
+
+ $vite->withEntryPoints(['resources/js/app.js'])->useHotFile('cold');
+
+ $this->assertSame(
+ ''
+ .'',
+ $vite->toHtml()
+ );
+
+ $this->cleanViteHotFile('cold');
+ }
+
protected function makeViteManifest($contents = null, $path = 'build')
{
app()->singleton('path.public', fn () => __DIR__);
@@ -582,28 +627,32 @@ protected function makeViteManifest($contents = null, $path = 'build')
file_put_contents(public_path("{$path}/manifest.json"), $manifest);
}
- protected function cleanViteManifest()
+ protected function cleanViteManifest($path = 'build')
{
- if (file_exists(public_path('build/manifest.json'))) {
- unlink(public_path('build/manifest.json'));
+ if (file_exists(public_path("{$path}/manifest.json"))) {
+ unlink(public_path("{$path}/manifest.json"));
}
- if (file_exists(public_path('build'))) {
- rmdir(public_path('build'));
+ if (file_exists(public_path($path))) {
+ rmdir(public_path($path));
}
}
- protected function makeViteHotFile()
+ protected function makeViteHotFile($path = null)
{
app()->singleton('path.public', fn () => __DIR__);
- file_put_contents(public_path('hot'), 'http://localhost:3000');
+ $path ??= public_path('hot');
+
+ file_put_contents($path, 'http://localhost:3000');
}
- protected function cleanViteHotFile()
+ protected function cleanViteHotFile($path = null)
{
- if (file_exists(public_path('hot'))) {
- unlink(public_path('hot'));
+ $path ??= public_path('hot');
+
+ if (file_exists($path)) {
+ unlink($path);
}
}
}