Skip to content

Commit

Permalink
[9.x] Add configurable paths to Vite (laravel#43620)
Browse files Browse the repository at this point in the history
* [9.x] Add configurable paths to Vite

* Update facade

* Add tests

* Revert import

* Do not enforce starting slashes

* Add public path resolver

* formatting

* resolve build directory from invoke

* formatting

* formatting

* move method

Co-authored-by: Tim MacDonald <[email protected]>
Co-authored-by: Taylor Otwell <[email protected]>
  • Loading branch information
3 people committed Aug 26, 2022
1 parent 7789bea commit cbf8690
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 26 deletions.
110 changes: 102 additions & 8 deletions src/Illuminate/Foundation/Vite.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
*
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -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);
}
Expand All @@ -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)) {
Expand All @@ -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.
*
Expand All @@ -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();
}
}
3 changes: 3 additions & 0 deletions src/Illuminate/Support/Facades/Vite.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
85 changes: 67 additions & 18 deletions tests/Foundation/FoundationViteTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand Down Expand Up @@ -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(
'<script type="module" src="https://example.com/build/assets/app.versioned.js"></script>',
$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(
'<script type="module" src="https://example.com/custom-build/assets/app.versioned.js"></script>',
$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(
'<script type="module" src="http://localhost:3000/@vite/client"></script>'
.'<script type="module" src="http://localhost:3000/resources/js/app.js"></script>',
$vite->toHtml()
);

$this->cleanViteHotFile('cold');
}

protected function makeViteManifest($contents = null, $path = 'build')
{
app()->singleton('path.public', fn () => __DIR__);
Expand Down Expand Up @@ -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);
}
}
}

0 comments on commit cbf8690

Please sign in to comment.