Skip to content

Commit

Permalink
Vite Locator interface improved to enable relative path handling
Browse files Browse the repository at this point in the history
Also includes tests, code improvements and fixes.
  • Loading branch information
dakujem committed Jan 3, 2023
1 parent 724d641 commit 6f84ced
Show file tree
Hide file tree
Showing 16 changed files with 534 additions and 30 deletions.
27 changes: 25 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
#
# +--------------------------------------------+
# | IDEs & platform ballast |
# +--------------------------------------------+
#
.idea
vendor
composer.lock


#
# +--------------------------------------------+
# | Vendor & Composer stuff |
# +--------------------------------------------+
#
vendor/*
composer.lock


#
# +--------------------------------------------+
# | Build & test artefacts |
# +--------------------------------------------+
#
tests/output/*
!tests/output/.gitkeep
tests/workdir/*
!tests/workdir/.gitkeep
17 changes: 16 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "dakujem/peat",
"description": "PHP-Vite.js bridging tool, framework-agnostic",
"license": "Unlicense",
"keywords": ["vite", "bridge"],
"authors": [
Expand All @@ -11,11 +12,25 @@
"require": {
"php": "^7.4 || ^8",
"ext-json": "*",
"symfony/polyfill-php80": "^1"
"symfony/polyfill-php80": "^1.15"
},
"require-dev": {
"nette/tester": "^2.4.1",
"tracy/tracy": "^2.8.9"
},
"autoload": {
"psr-4": {
"Dakujem\\Peat\\": "src/"
}
},
"scripts": {
"test": "@test:local",
"test:local": "@php vendor/nette/tester/src/tester tests -C --colors 1",
"test:ci": "tester tests"
},
"scripts-descriptions": {
"test": "Run application tests. (defaults to local tests)",
"test:local": "Run application tests with local configuration.",
"test:ci": "Run application tests, provide configuration options as needed."
}
}
7 changes: 4 additions & 3 deletions src/CollectiveLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ public function __construct(/*ViteLocatorContract|callable|null*/ ...$locators)
}
}

public function entry(string $name): ?ViteEntryAsset
public function entry(string $name, ?string $relativeOffset = null): ?ViteEntryAsset
{
$entryName = ltrim($name, '/');
foreach ($this->locators as $step) {
$asset = $step instanceof ViteLocatorContract ? $step->entry($entryName) : $step($entryName);
$asset = $step instanceof ViteLocatorContract ?
$step->entry($name, $relativeOffset) :
$step($name, $relativeOffset);
if ($asset !== null) {
return $asset;
}
Expand Down
10 changes: 6 additions & 4 deletions src/ConditionalLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,23 @@ final class ConditionalLocator implements ViteLocatorContract
{
/** @var callable */
private $condition;
private ViteLocatorContract $serverLocator;
private ViteLocatorContract $locator;

public function __construct(callable $condition, ViteLocatorContract $locator)
{
$this->condition = $condition;
$this->serverLocator = $locator;
$this->locator = $locator;
}

public function __invoke(string $entryName): ?ViteEntryAsset
{
return $this->entry($entryName);
}

public function entry(string $name): ?ViteEntryAsset
public function entry(string $name, ?string $relativeOffset = null): ?ViteEntryAsset
{
return ($this->condition)($name) ? $this->serverLocator->entry($name) : null;
return ($this->condition)($name, $relativeOffset) ?
$this->locator->entry($name, $relativeOffset) :
null;
}
}
22 changes: 16 additions & 6 deletions src/ViteBridge.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class ViteBridge
{
private string $manifestFile;
private ?string $cacheFile;
private string $assetPath;
private string $assetPathPrefix;
private ?string $devServerUrl;
private bool $strict;

Expand All @@ -26,20 +26,20 @@ final class ViteBridge
*
* @param string $manifestFile Path to the Vite-generated manifest json file.
* @param string|null $cacheFile This is where this locator stores (and reads from) its cache file. Must be writable.
* @param string $assetPath This will typically be relative path from the public dir to the dir with assets, or empty string ''.
* @param string $assetPathPrefix This will typically be relative path from the public dir to the dir with assets, or empty string ''.
* @param ?string $devServerUrl Vite's dev server URL (development only).
* @param bool $strict Locators throw exceptions in strict mode, silently fail in lax mode.
*/
public function __construct(
string $manifestFile,
?string $cacheFile = null,
string $assetPath = '',
string $assetPathPrefix = '',
?string $devServerUrl = null,
bool $strict = false
) {
$this->manifestFile = $manifestFile;
$this->cacheFile = $cacheFile;
$this->assetPath = $assetPath;
$this->assetPathPrefix = $assetPathPrefix;
$this->devServerUrl = $devServerUrl;
$this->strict = $strict;
}
Expand All @@ -61,7 +61,12 @@ public function makePassiveEntryLocator(
return new ViteServerLocator($this->devServerUrl);
}
// Otherwise, the assets are served from a bundle (build).
$bundleLocator = new ViteBuildLocator($this->manifestFile, $this->cacheFile, $this->assetPath, $this->strict);
$bundleLocator = new ViteBuildLocator(
$this->manifestFile,
$this->cacheFile,
$this->assetPathPrefix,
$this->strict,
);
if (!$this->strict) {
return $bundleLocator;
}
Expand All @@ -80,7 +85,12 @@ function (string $name) {
*/
public function populateCache(): void
{
(new ViteBuildLocator($this->manifestFile, $this->cacheFile, $this->assetPath, $this->strict))
(new ViteBuildLocator(
$this->manifestFile,
$this->cacheFile,
$this->assetPathPrefix,
$this->strict,
))
->populateCache();
}
}
25 changes: 15 additions & 10 deletions src/ViteBuildLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,26 @@
final class ViteBuildLocator implements ViteLocatorContract
{
private ?array $map = null;
private string $assetPath;
private string $assetPathPrefix;
private string $manifestFile;
private ?string $cacheFile;
private bool $strict;

/**
* @param string $manifestFile Path to the Vite-generated manifest json file.
* @param string|null $cacheFile This is where this locator stores (and reads from) its cache file. Must be writable.
* @param string $assetPath This will typically be relative path from the public dir to the dir with assets, or empty string ''.
* @param string $assetPathPrefix This will typically be relative path from the public dir to the dir with assets, or empty string ''.
* @param bool $strict In strict mode (default), an exception is thrown on invalid read of the manifest file.
*/
public function __construct(
string $manifestFile,
?string $cacheFile = null,
string $assetPath = '',
string $assetPathPrefix = '',
bool $strict = true
) {
$this->manifestFile = $manifestFile;
$this->cacheFile = $cacheFile;
$this->assetPath = $assetPath !== '' && $assetPath !== '/' ? rtrim($assetPath, '/') : '';
$this->assetPathPrefix = $assetPathPrefix !== '' && $assetPathPrefix !== '/' ? rtrim($assetPathPrefix, '/') . '/' : $assetPathPrefix;
$this->strict = $strict;
}

Expand All @@ -50,16 +50,17 @@ public function __invoke(string $entryName): ?ViteEntryAsset
* The asset object can be type cast to string containing HTML tags.
*
* @param string $name asset entry name, as found in the Vite-generated manifest.json
* @param string|null $relativeOffset utilized when relative asset paths are in use
* @return ViteEntryAsset|null
*/
public function entry(string $name): ?ViteEntryAsset
public function entry(string $name, ?string $relativeOffset = null): ?ViteEntryAsset
{
$map = $this->loadAssetMap();
$chunk = $map[$name] ?? null;
if ($chunk === null) {
return null;
}
$path = fn(?string $v): ?string => $v !== null ? $this->prefix($v, $this->assetPath) : null;
$path = fn(?string $v): ?string => $v !== null ? $this->buildPath($v, $relativeOffset) : null;
$imports = array_filter(
array_map(fn(string $import) => $path($map[$import]['file'] ?? null), $chunk['imports'] ?? [])
);
Expand All @@ -69,9 +70,13 @@ public function entry(string $name): ?ViteEntryAsset
);
}

private function prefix(string $path, ?string $prefix = null): string
private function buildPath(string $asset, ?string $relativeOffset = null): string
{
return ($prefix !== null ? $prefix . '/' : '') . $path;
$basePrefix = $this->assetPathPrefix;
if ($relativeOffset !== null && $relativeOffset !== '') {
$relativeOffset = rtrim($relativeOffset, '/') . '/';
}
return $relativeOffset . $basePrefix . $asset;
}

/**
Expand All @@ -84,7 +89,7 @@ private function prefix(string $path, ?string $prefix = null): string
public function populateCache(): self
{
if ($this->cacheFile === null) {
throw new LogicException('Path to where a cache file can be written has not been provided.');
throw new LogicException('Path where Peat cache file can be written to has not been provided.');
}
$map = $this->readManifest(
$this->manifestFile,
Expand Down Expand Up @@ -120,7 +125,7 @@ private function writeCacheFile(array $map, string $cacheFile): void
{
$f = @fopen($cacheFile, 'w');
if (!$f) {
throw new RuntimeException('Vite cache file not writable: ' . $cacheFile);
throw new RuntimeException('Peat cache file not writable: ' . $cacheFile);
}
$export = var_export($map, true);
$content = "<?php\nreturn {$export};\n";
Expand Down
4 changes: 2 additions & 2 deletions src/ViteEntryAsset.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public function __toString(): string
public function jsonSerialize(): array
{
return [
'modules' => $this->modules(),
'css' => $this->css(),
'modules' => $this->modules,
'css' => $this->css,
];
}
}
2 changes: 1 addition & 1 deletion src/ViteLocatorContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@
*/
interface ViteLocatorContract
{
public function entry(string $name): ?ViteEntryAsset;
public function entry(string $name, ?string $relativeOffset = null): ?ViteEntryAsset;
}
4 changes: 3 additions & 1 deletion src/ViteServerLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ public function __invoke(string $entryName): ?ViteEntryAsset
/**
* If the server URL is set, this call always returns a URL, because it does not detect existence of the asset.
*/
public function entry(string $name): ?ViteEntryAsset
public function entry(string $name, ?string $relativeOffset = null): ?ViteEntryAsset
{
if ($this->liveHost !== null) {
// Note: Relative offset is ignored in this setup on purpose.
return $this->serveLive($name, $this->liveHost);
}
return null;
Expand All @@ -47,6 +48,7 @@ private function serveLive(string $asset, string $host): ViteEntryAsset
[
$host . '/' . self::CLIENT_SCRIPT,
$host . '/' . $asset,
// $host . '/' . ltrim($asset, '/'), // this would not be coherent with build locator
],
);
}
Expand Down
47 changes: 47 additions & 0 deletions tests/ViteAsset.default.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);


namespace Dakujem\Trest;

require_once __DIR__ . '/common.php';

use Dakujem\Peat\ViteEntryAsset;
use Tester\Assert;
use Tester\TestCase;

/**
* This test tests the capabilities on the official Vite backend integration example.
*
* @author Andrej Rypak (dakujem) <[email protected]>
*/
class _DefaultViteAssetTest extends TestCase
{
public function testEmptyAsset()
{
$asset = new ViteEntryAsset();

Assert::same('', (string)$asset);
Assert::same([], $asset->modules());
Assert::same([], $asset->css());
Assert::same(['modules' => [], 'css' => [],], $asset->jsonSerialize());
}

public function testNonEmptyAsset()
{
$asset = new ViteEntryAsset(['a', 'b'], ['c', 'd']);

Assert::same('<script type="module" src="a"></script>' . "\n" .
'<script type="module" src="b"></script>' . "\n" .
'<link rel="stylesheet" href="c" />' . "\n" .
'<link rel="stylesheet" href="d" />'
, (string)$asset);
Assert::same(['a', 'b'], $asset->modules());
Assert::same(['c', 'd'], $asset->css());
Assert::same(['modules' => ['a', 'b'], 'css' => ['c', 'd'],], $asset->jsonSerialize());
}
}

// run the test
(new _DefaultViteAssetTest)->run();
Loading

0 comments on commit 6f84ced

Please sign in to comment.