Skip to content

Commit

Permalink
add EntrypointRenderer and TagRenderer tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lhapaipai committed Oct 31, 2023
1 parent 321507a commit 014971c
Show file tree
Hide file tree
Showing 18 changed files with 970 additions and 150 deletions.
115 changes: 65 additions & 50 deletions src/Asset/EntrypointRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ class EntrypointRenderer
private EntrypointsLookupCollection $entrypointsLookupCollection;
private TagRendererCollection $tagRendererCollection;
private bool $useAbsoluteUrl;
private RouterInterface $router;
private EventDispatcherInterface $eventDispatcher;
private ?RouterInterface $router;
private ?EventDispatcherInterface $eventDispatcher;

private $returnedViteClient = false;
private $returnedReactRefresh = false;
private $returnedPreloadedScripts = [];
private $returnedViteClients = [];
private $returnedReactRefresh = [];
private $returnedViteLegacyScripts = [];

private $hasReturnedViteLegacyScripts = false;
private $renderedFiles = [];

public function __construct(
EntrypointsLookupCollection $entrypointsLookupCollection,
Expand Down Expand Up @@ -57,7 +57,7 @@ private function shouldUseAbsoluteURL(array $options, $configName)
{
$viteServer = $this->getEntrypointsLookup($configName)->getViteServer($configName);

return false === $viteServer && ($this->useAbsoluteUrl || (isset($options['absolute_url']) && true === $options['absolute_url']));
return is_null($viteServer) && ($this->useAbsoluteUrl || (isset($options['absolute_url']) && true === $options['absolute_url']));
}

public function getMode(string $configName = null): ?string
Expand All @@ -73,9 +73,10 @@ public function getMode(string $configName = null): ?string

public function reset()
{
// resets the state of this service
$this->returnedViteClient = false;
$this->returnedReactRefresh = false;
$this->returnedViteClients = [];
$this->returnedReactRefresh = [];
$this->returnedViteLegacyScripts = [];
$this->renderedFiles = [];
}

public function renderScripts(
Expand All @@ -96,25 +97,27 @@ public function renderScripts(
$tags = [];
$viteServer = $entrypointsLookup->getViteServer();
$isBuild = $entrypointsLookup->isBuild();
$base = $entrypointsLookup->getBase();

if (false !== $viteServer) {
if (!is_null($viteServer)) {
// vite server is active
if (!$this->returnedViteClient) {
$tags[] = $tagRenderer->createViteClientScript($viteServer['origin'].$viteServer['base'].'@vite/client');
$this->returnedViteClient = true;
if (!isset($this->returnedViteClients[$configName])) {
$tags[] = $tagRenderer->createViteClientScript($viteServer.$base.'@vite/client');

$this->returnedViteClients[$configName] = true;
}

if (
!$this->returnedReactRefresh
!isset($this->returnedReactRefresh[$configName])
&& isset($options['dependency']) && 'react' === $options['dependency']
) {
$tags[] = $tagRenderer->createReactRefreshScript($viteServer['origin'].$viteServer['base']);
$tags[] = $tagRenderer->createReactRefreshScript($viteServer.$base);

$this->$this->returnedReactRefresh = true;
$this->returnedReactRefresh[$configName] = true;
}
} elseif (
$entrypointsLookup->isLegacyPluginEnabled()
&& !$this->hasReturnedViteLegacyScripts
&& !isset($this->returnedViteLegacyScripts[$configName])
) {
/* legacy section when vite server is inactive */
$tags[] = $tagRenderer->createDetectModernBrowserScript();
Expand All @@ -132,39 +135,48 @@ public function renderScripts(
]
);
}
$this->hasReturnedViteLegacyScripts = true;

$this->returnedViteLegacyScripts[$configName] = true;
}

/* normal js scripts */
foreach ($entrypointsLookup->getJSFiles($entryName) as $filePath) {
$tags[] = $tagRenderer->createScriptTag(
array_merge(
[
'type' => 'module',
'src' => $this->completeURL($filePath, $useAbsoluteUrl),
'integrity' => $entrypointsLookup->getFileHash($filePath),
],
$options['attr'] ?? []
)
);
if (false === \in_array($filePath, $this->renderedFiles, true)) {
$tags[] = $tagRenderer->createScriptTag(
array_merge(
[
'type' => 'module',
'src' => $this->completeURL($filePath, $useAbsoluteUrl),
'integrity' => $entrypointsLookup->getFileHash($filePath),
],
$options['attr'] ?? []
)
);

$this->renderedFiles[] = $filePath;
}
}

/* legacy js scripts */
if ($entrypointsLookup->hasLegacy($entryName)) {
$id = self::pascalToKebab("vite-legacy-entry-$entryName");

$file = $entrypointsLookup->getLegacyJSFile($entryName);
$tags[] = $tagRenderer->createScriptTag(
[
'nomodule' => true,
'data-src' => $this->completeURL($file, $useAbsoluteUrl),
'id' => $id,
'crossorigin' => true,
'class' => 'vite-legacy-entry',
'integrity' => $entrypointsLookup->getFileHash($file),
],
InlineContent::getSystemJSInlineCode($id)
);
$filePath = $entrypointsLookup->getLegacyJSFile($entryName);
if (false === \in_array($filePath, $this->renderedFiles, true)) {
$tags[] = $tagRenderer->createScriptTag(
[
'nomodule' => true,
'data-src' => $this->completeURL($filePath, $useAbsoluteUrl),
'id' => $id,
'crossorigin' => true,
'class' => 'vite-legacy-entry',
'integrity' => $entrypointsLookup->getFileHash($filePath),
],
InlineContent::getSystemJSInlineCode($id)
);

$this->renderedFiles[] = $filePath;
}
}

return $this->renderTags($tags, $isBuild, $toString);
Expand All @@ -189,32 +201,35 @@ public function renderLinks(
$tags = [];

foreach ($entrypointsLookup->getCSSFiles($entryName) as $filePath) {
$tags[] = $tagRenderer->createLinkStylesheetTag(
$this->completeURL($filePath, $useAbsoluteUrl),
array_merge(['integrity' => $entrypointsLookup->getFileHash($filePath)], $options['attr'] ?? [])
);
if (false === \in_array($filePath, $this->renderedFiles, true)) {
$tags[] = $tagRenderer->createLinkStylesheetTag(
$this->completeURL($filePath, $useAbsoluteUrl),
array_merge(['integrity' => $entrypointsLookup->getFileHash($filePath)], $options['attr'] ?? [])
);
$this->renderedFiles[] = $filePath;
}
}

if ($isBuild) {
foreach ($entrypointsLookup->getJavascriptDependencies($entryName) as $filePath) {
if (false === \in_array($filePath, $this->returnedPreloadedScripts, true)) {
if (false === \in_array($filePath, $this->renderedFiles, true)) {
$tags[] = $tagRenderer->createModulePreloadLinkTag(
$this->completeURL($filePath, $useAbsoluteUrl),
['integrity' => $entrypointsLookup->getFileHash($filePath)]
);
$this->returnedPreloadedScripts[] = $filePath;
$this->renderedFiles[] = $filePath;
}
}
}

if ($isBuild && isset($options['preloadDynamicImports']) && true === $options['preloadDynamicImports']) {
foreach ($entrypointsLookup->getJavascriptDynamicDependencies($entryName) as $filePath) {
if (false === \in_array($filePath, $this->returnedPreloadedScripts, true)) {
if (false === \in_array($filePath, $this->renderedFiles, true)) {
$tags[] = $tagRenderer->createModulePreloadLinkTag(
$this->completeURL($filePath, $useAbsoluteUrl),
['integrity' => $entrypointsLookup->getFileHash($filePath)]
);
$this->returnedPreloadedScripts[] = $filePath;
$this->renderedFiles[] = $filePath;
}
}
}
Expand All @@ -231,7 +246,7 @@ public function renderTags(array $tags, $isBuild, $toString)
}

return $toString
? implode(PHP_EOL, array_map(function ($tagEvent) {
? implode('', array_map(function ($tagEvent) {
return TagRenderer::generateTag($tagEvent);
}, $tags))
: $tags;
Expand Down
14 changes: 11 additions & 3 deletions src/Asset/EntrypointsLookup.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ private function getFileContent(): array
throw new \Exception('entrypoints.json not found at '.$this->fileInfos['entrypointsPath']);
}
$content = json_decode(file_get_contents($this->fileInfos['entrypointsPath']), true);
if (!isset($content['entryPoints'], $content['viteServer'])) {
throw new \Exception($this->fileInfos['entrypointsPath'].' : entryPoints or viteServer not exists');
if (!array_key_exists('entryPoints', $content)
|| !array_key_exists('viteServer', $content)
|| !array_key_exists('base', $content)
) {
throw new \Exception($this->fileInfos['entrypointsPath'].' : entryPoints, base or viteServer not exists');
}

$this->fileInfos['content'] = $content;
Expand Down Expand Up @@ -67,14 +70,19 @@ public function isLegacyPluginEnabled(): bool

public function isBuild(): bool
{
return false === $this->getFileContent()['viteServer'];
return null === $this->getFileContent()['viteServer'];
}

public function getViteServer()
{
return $this->getFileContent()['viteServer'];
}

public function getBase()
{
return $this->getFileContent()['base'];
}

public function getJSFiles($entryName): array
{
$this->throwIfEntrypointIsMissing($entryName);
Expand Down
19 changes: 19 additions & 0 deletions src/Asset/Tag.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,30 @@ public function isLinkTag(): bool
return self::LINK_TAG === $this->tagName;
}

public function isStylesheet(): bool
{
return self::LINK_TAG === $this->tagName
&& isset($this->attributes['rel'])
&& 'stylesheet' === $this->attributes['rel'];
}

public function isModulePreload(): bool
{
return self::LINK_TAG === $this->tagName
&& isset($this->attributes['rel'])
&& 'modulepreload' === $this->attributes['rel'];
}

public function getAttributes(): array
{
return $this->attributes;
}

public function getAttribute($key): mixed
{
return key_exists($key, $this->attributes) ? $this->attributes[$key] : null;
}

/**
* @param string $name The attribute name
* @param string|bool $value Value can be "true" to have an attribute without a value (e.g. "defer")
Expand Down
39 changes: 22 additions & 17 deletions src/Asset/ViteAssetVersionStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,52 @@
class ViteAssetVersionStrategy implements VersionStrategyInterface
{
private string $publicPath;
private array $builds;
private array $configs;
private $useAbsoluteUrl;
private $router;

private string $manifestPath;
private string $entrypointsPath;
private $manifestData;
private $entrypointsData;
private ?array $build = null;
private ?array $config = null;
private bool $strictMode;
private ?string $mode = null;

public function __construct(
string $publicPath,
array $builds,
string $defaultBuildName,
array $configs,
string $defaultConfigName,
bool $useAbsoluteUrl,
RouterInterface $router = null,
bool $strictMode = true
) {
$this->publicPath = $publicPath;
$this->builds = $builds;
$this->configs = $configs;
$this->strictMode = $strictMode;
$this->useAbsoluteUrl = $useAbsoluteUrl;
$this->router = $router;

$this->setBuildName($defaultBuildName);
$this->setConfig($defaultConfigName);

if (($scheme = parse_url($this->manifestPath, \PHP_URL_SCHEME)) && 0 === strpos($scheme, 'http')) {
throw new \Exception('You can\'t use a remote manifest with ViteAssetVersionStrategy');
}
}

public function setBuildName(string $buildName): void
public function setConfig(string $configName): void
{
$this->build = $this->builds[$buildName];
$this->manifestPath = $this->publicPath.$this->build['base'].'manifest.json';
$this->entrypointsPath = $this->publicPath.$this->build['base'].'entrypoints.json';
$this->mode = null;
$this->config = $this->configs[$configName];
$this->manifestPath = $this->publicPath.$this->config['base'].'manifest.json';
$this->entrypointsPath = $this->publicPath.$this->config['base'].'entrypoints.json';
}

/**
* With a entrypoints, we don't really know or care about what
* the version is. Instead, this returns the path to the
* versioned file.
* versioned file. as it contains a hashed and different path
* with each new config, this is enough for us.
*/
public function getVersion(string $path): string
{
Expand All @@ -75,19 +78,21 @@ private function completeURL(string $path)

private function getassetsPath(string $path): ?string
{
if (null === $this->manifestData) {
if (null === $this->mode) {
if (!is_file($this->entrypointsPath)) {
throw new RuntimeException(sprintf('assets entrypoints file "%s" does not exist. Did you forget configure your base in pentatrion_vite.yml?', $this->manifestPath));
throw new RuntimeException(sprintf('assets entrypoints file "%s" does not exist. Did you forget configure your `build_dir` in pentatrion_vite.yml?', $this->entrypointsPath));
}

if (is_file($this->manifestPath)) {
// when vite server is running manifest file doesn't exists
$this->mode = 'build';
try {
$this->manifestData = json_decode(file_get_contents($this->manifestPath), true, 512, \JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
throw new RuntimeException(sprintf('Error parsing JSON from entrypoints file "%s": ', $this->manifestPath).$e->getMessage(), 0, $e);
}
} else {
$this->manifestData = false;
$this->mode = 'dev';
try {
$this->entrypointsData = json_decode(file_get_contents($this->entrypointsPath), true, 512, \JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
Expand All @@ -96,12 +101,12 @@ private function getassetsPath(string $path): ?string
}
}

if (false !== $this->manifestData) {
if ('build' === $this->mode) {
if (isset($this->manifestData[$path])) {
return $this->completeURL($this->build['base'].$this->manifestData[$path]['file']);
return $this->completeURL($this->config['base'].$this->manifestData[$path]['file']);
}
} else {
return $this->entrypointsData['viteServer']['origin'].$this->entrypointsData['viteServer']['base'].$path;
return $this->entrypointsData['viteServer'].$this->entrypointsData['base'].$path;
}

if ($this->strictMode) {
Expand Down
Loading

0 comments on commit 014971c

Please sign in to comment.