Skip to content

Commit

Permalink
Refactor and StyleCI updates
Browse files Browse the repository at this point in the history
Replaced nullsafe with isset check
Created vite() helper to replicate the functionality of the mix() helper
Abstracted vite() helper method into Vite foundation class
Added tests for generation of single URL path
  • Loading branch information
chrispage1 committed Jul 8, 2022
1 parent 1beaaf5 commit 8bed08c
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 26 deletions.
99 changes: 73 additions & 26 deletions src/Illuminate/Foundation/Vite.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Illuminate\Foundation;

use Exception;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Str;

Expand All @@ -24,49 +23,36 @@ public function __invoke($entrypoints, $buildDirectory = 'build')
$entrypoints = collect($entrypoints);
$buildDirectory = Str::start($buildDirectory, '/');

if (is_file(public_path('/hot'))) {
$url = rtrim(file_get_contents(public_path('/hot')));

if ($hotServer = $this->hotServer()) {
return new HtmlString(
$entrypoints
->map(fn ($entrypoint) => $this->makeTag("{$url}/{$entrypoint}"))
->prepend($this->makeScriptTag("{$url}/@vite/client"))
->map(fn ($entrypoint) => $this->makeTag("$hotServer/$entrypoint"))
->prepend($this->makeScriptTag("$hotServer/@vite/client"))
->join('')
);
}

$manifestPath = public_path($buildDirectory.'/manifest.json');

if (! isset($manifests[$manifestPath])) {
if (! is_file($manifestPath)) {
throw new Exception("Vite manifest not found at: {$manifestPath}");
}

$manifests[$manifestPath] = json_decode(file_get_contents($manifestPath), true);
}

$manifest = $manifests[$manifestPath];

$tags = collect();
$manifest = $this->manifestContents($buildDirectory);

foreach ($entrypoints as $entrypoint) {
if (! isset($manifest[$entrypoint])) {
throw new Exception("Unable to locate file in Vite manifest: {$entrypoint}.");
throw new \Exception("Unable to locate file in Vite manifest: {$entrypoint}.");
}

$tags->push($this->makeTag(asset("{$buildDirectory}/{$manifest[$entrypoint]['file']}")));
$tags->push($this->makeTag(asset("$buildDirectory/{$manifest[$entrypoint]['file']}")));

if (isset($manifest[$entrypoint]['css'])) {
foreach ($manifest[$entrypoint]['css'] as $css) {
$tags->push($this->makeStylesheetTag(asset("{$buildDirectory}/{$css}")));
$tags->push($this->makeStylesheetTag(asset("$buildDirectory/$css")));
}
}

if (isset($manifest[$entrypoint]['imports'])) {
foreach ($manifest[$entrypoint]['imports'] as $import) {
if (isset($manifest[$import]['css'])) {
foreach ($manifest[$import]['css'] as $css) {
$tags->push($this->makeStylesheetTag(asset("{$buildDirectory}/{$css}")));
$tags->push($this->makeStylesheetTag(asset("$buildDirectory/$css")));
}
}
}
Expand All @@ -78,19 +64,41 @@ public function __invoke($entrypoints, $buildDirectory = 'build')
return new HtmlString($stylesheets->join('').$scripts->join(''));
}

/**
* Retrieve a single Vite absolute resource URL.
*
* @param string $resourcePath
* @param string $buildDirectory
* @return string
*
* @throws \Exception
*/
public function resourceUrl($resourcePath, $buildDirectory = 'build')
{
if ($hotServer = $this->hotServer()) {
return "$hotServer/$resourcePath";
}

$manifest = $this->manifestContents($buildDirectory);

if (! isset($manifest[$resourcePath]['file'])) {
throw new \Exception('Unknown Vite entrypoint '.$resourcePath);
}

return asset(Str::start($buildDirectory.'/'.$manifest[$resourcePath]['file'], '/'));
}

/**
* Generate React refresh runtime script.
*
* @return \Illuminate\Support\HtmlString|void
*/
public function reactRefresh()
{
if (! is_file(public_path('/hot'))) {
if (! $hotServer = $this->hotServer()) {
return;
}

$url = rtrim(file_get_contents(public_path('/hot')));

return new HtmlString(
sprintf(
<<<'HTML'
Expand All @@ -102,11 +110,50 @@ public function reactRefresh()
window.__vite_plugin_react_preamble_installed__ = true
</script>
HTML,
$url
$hotServer
)
);
}

/**
* Retrieve our manifest file contents.
*
* @param string $buildDirectory
* @return array
*
* @throws \Exception
*/
protected function manifestContents($buildDirectory = 'build')
{
static $manifests = [];

$manifestPath = public_path($buildDirectory.'/manifest.json');

if (! isset($manifests[$manifestPath])) {
if (! is_file($manifestPath)) {
throw new \Exception("Vite manifest not found at: {$manifestPath}");
}

$manifests[$manifestPath] = json_decode(file_get_contents($manifestPath), true);
}

return $manifests[$manifestPath];
}

/**
* Return the path to the Vite hot-reload server when available.
*
* @return string|null
*/
protected function hotServer(): string|null
{
if (is_file(public_path('/hot'))) {
return rtrim(file_get_contents(public_path('/hot')));
}

return null;
}

/**
* Generate an appropriate tag for the given URL.
*
Expand Down
21 changes: 21 additions & 0 deletions src/Illuminate/Foundation/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Illuminate\Foundation\Bus\PendingClosureDispatch;
use Illuminate\Foundation\Bus\PendingDispatch;
use Illuminate\Foundation\Mix;
use Illuminate\Foundation\Vite;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Queue\CallQueuedClosure;
use Illuminate\Support\Facades\Date;
Expand Down Expand Up @@ -559,6 +560,26 @@ function mix($path, $manifestDirectory = '')
}
}

if (! function_exists('vite')) {

/**
* Get the path to a Vite asset.
*
* @param string $resourcePath The asset entrypoint to load
* @param string $buildDirectory Vite build directory
* @return string
*
* @throws \Exception
*/
function vite($resourcePath, $buildDirectory = 'build')
{
/** @var Vite $vite */
$vite = app(Vite::class);

return $vite->resourceUrl($resourcePath, $buildDirectory);
}
}

if (! function_exists('now')) {
/**
* Create a new Carbon instance for the current time.
Expand Down
18 changes: 18 additions & 0 deletions tests/Foundation/FoundationViteTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,24 @@ public function testViteHotModuleReplacementWithJsAndCss()
);
}

public function testViteHotModuleSingleFileUriResolution()
{
$this->makeViteHotFile();

$result = (new Vite)->resourceUrl('resources/css/app.css');

$this->assertEquals('http://localhost:3000/resources/css/app.css', $result);
}

public function testViteBuildSingleFileManifestResolution()
{
$this->makeViteManifest();

$result = (new Vite)->resourceUrl('resources/css/app.css');

$this->assertEquals('https://example.com/build/assets/app.versioned.css', $result);
}

protected function makeViteManifest()
{
app()->singleton('path.public', fn () => __DIR__);
Expand Down

0 comments on commit 8bed08c

Please sign in to comment.