From 2677ae1d91c0394abd227d902238027ff10d87cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Mat=C4=9Bj=C4=8Dek?= Date: Thu, 2 Jun 2022 10:26:48 +0200 Subject: [PATCH 1/3] add extension --- Vite/src/AssetFilter.php | 21 ++++++++ Vite/src/Nette/Extension.php | 100 +++++++++++++++++++++++++++++++++++ Vite/src/Service.php | 92 ++++++++++++++++++++++++++++++++ Vite/src/Tracy/Vite.html | 47 ++++++++++++++++ Vite/src/Tracy/VitePanel.php | 20 +++++++ Vite/src/ViteToTemplate.php | 13 +++++ composer.json | 3 +- 7 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 Vite/src/AssetFilter.php create mode 100644 Vite/src/Nette/Extension.php create mode 100644 Vite/src/Service.php create mode 100644 Vite/src/Tracy/Vite.html create mode 100644 Vite/src/Tracy/VitePanel.php create mode 100644 Vite/src/ViteToTemplate.php diff --git a/Vite/src/AssetFilter.php b/Vite/src/AssetFilter.php new file mode 100644 index 0000000..566027c --- /dev/null +++ b/Vite/src/AssetFilter.php @@ -0,0 +1,21 @@ +vite = $vite; + } + + + public function __invoke(string $path): string + { + return $this->vite->getAsset($path); + } + +} diff --git a/Vite/src/Nette/Extension.php b/Vite/src/Nette/Extension.php new file mode 100644 index 0000000..3e89eb5 --- /dev/null +++ b/Vite/src/Nette/Extension.php @@ -0,0 +1,100 @@ + Schema\Expect::string('http://localhost:3000'), + 'debugMode' => Schema\Expect::bool($this->getContainerBuilder()->parameters['debugMode'] ?? false), + 'manifestFile' => Schema\Expect::string()->required(), + 'filterName' => Schema\Expect::string('asset'), // empty string is for disabled + 'templateProperty' => Schema\Expect::string('_vite'), // empty string is for disabled and you can use ViteToTemplate for Presenter + ]); + } + + + public function loadConfiguration(): void + { + $this->buildViteService(); + $this->buildFilter(); + } + + + private function buildViteService(): void + { + $this->getContainerBuilder()->addDefinition($this->prefix('service')) + ->setFactory(Service::class) + ->setArguments([ + 'viteServer' => $this->config->server, + 'manifestFile' => $this->config->manifestFile, + 'debugMode' => $this->config->debugMode, + ]); + } + + + private function buildFilter(): void + { + $this->getContainerBuilder()->addDefinition($this->prefix('assetFilter')) + ->setFactory(AssetFilter::class) + ->setAutowired(false); + } + + + public function beforeCompile(): void + { + $builder = $this->getContainerBuilder(); + + $templateFactoryDefinition = $builder->getDefinition('latte.templateFactory'); + assert($templateFactoryDefinition instanceof Definitions\ServiceDefinition); + + if ($this->config->templateProperty !== '') { + $templateFactoryDefinition->addSetup( + new Nette\DI\Definitions\Statement('$onCreate[]', [ + new Definitions\Statement([ + self::class, + 'prepareTemplate', + ], [$this->config->templateProperty, $builder->getDefinition($this->prefix('service'))]), + ]) + ); + } + + if ($this->config->filterName !== '' && $builder->hasDefinition('latte.latteFactory')) { + $builder->getDefinition('latte.latteFactory') + ->getResultDefinition() + ->addSetup('addFilter', [ + $this->config->filterName, + $builder->getDefinition($this->prefix('assetFilter')), + ]); + } + + $tracyClass = Tracy\Bar::class; + if ($this->config->debugMode && $builder->getByType($tracyClass)) { + $this->getContainerBuilder()->getDefinition($this->prefix('service')) + ->addSetup("@$tracyClass::addPanel", [ + new Definitions\Statement(VitePanel::class), + ]); + } + } + + + public static function prepareTemplate(string $propertyName, Service $service): \Closure + { + return function (Nette\Application\UI\Template $template) use ($propertyName, $service): void { + $template->{$propertyName} = $service; + }; + } + +} diff --git a/Vite/src/Service.php b/Vite/src/Service.php new file mode 100644 index 0000000..5dfaf6a --- /dev/null +++ b/Vite/src/Service.php @@ -0,0 +1,92 @@ +viteServer = $viteServer; + $this->manifestFile = $manifestFile; + $this->debugMode = $debugMode; + $this->httpRequest = $httpRequest; + } + + + public function getAsset(string $entrypoint): string + { + $asset = ''; + $baseUrl = '/'; + + if (!$this->isEnabled()) { + if (file_exists($this->manifestFile)) { + $manifest = Json::decode(FileSystem::read($this->manifestFile), Json::FORCE_ARRAY); + $asset = $manifest[$entrypoint]['file']; + } else { + trigger_error('Missing manifest file: ' . $this->manifestFile, E_USER_WARNING); + } + } else { + $baseUrl = $this->viteServer . '/'; + $asset = $entrypoint; + } + + return $baseUrl . $asset; + } + + + public function getCssAssets(string $entrypoint): array + { + $assets = []; + + if (!$this->isEnabled()) { + if (file_exists($this->manifestFile)) { + $manifest = Json::decode(FileSystem::read($this->manifestFile), Json::FORCE_ARRAY); + $assets = $manifest[$entrypoint]['css'] ?? []; + } else { + trigger_error('Missing manifest file: ' . $this->manifestFile, E_USER_WARNING); + } + } + + return $assets; + } + + + public function isEnabled(): bool + { + return $this->debugMode && $this->httpRequest->getCookie('netteVite') === 'true'; + } + + + public function printTags(string $entrypoint): void + { + $scripts = [$this->getAsset($entrypoint)]; + $styles = $this->getCssAssets($entrypoint); + + if ($this->isEnabled()) { + echo Html::el('script')->type('module')->src($this->viteServer . '/' . '@vite/client'); + } + + foreach ($styles as $path) { + echo Html::el('link')->rel('stylesheet')->href($path); + } + + foreach ($scripts as $path) { + echo Html::el('script')->type('module')->src($path); + } + } + +} diff --git a/Vite/src/Tracy/Vite.html b/Vite/src/Tracy/Vite.html new file mode 100644 index 0000000..00d3543 --- /dev/null +++ b/Vite/src/Tracy/Vite.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Vite/src/Tracy/VitePanel.php b/Vite/src/Tracy/VitePanel.php new file mode 100644 index 0000000..22207f2 --- /dev/null +++ b/Vite/src/Tracy/VitePanel.php @@ -0,0 +1,20 @@ +onRender[] = static fn($presenter) => $presenter->getTemplate()->_vite = $vite; + } + +} diff --git a/composer.json b/composer.json index 704d2d8..08454bc 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,8 @@ }, "autoload": { "psr-4": { - "App\\": "app" + "App\\": "app", + "MMEE\\Vite\\": "Vite/src" } }, "minimum-stability": "stable" From 28f6b3891cacdebd18581bf16aab95533a9ceaec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Mat=C4=9Bj=C4=8Dek?= Date: Thu, 2 Jun 2022 10:37:30 +0200 Subject: [PATCH 2/3] use extension --- app/Latte/AssetFilter.php | 21 -------- app/Presenters/BasePresenter.php | 7 --- app/Services/Vite.php | 91 -------------------------------- app/Tracy/Vite/Vite.html | 49 ----------------- app/Tracy/Vite/Vite.php | 14 ----- config/common.neon | 4 -- config/services.neon | 11 ++-- 7 files changed, 7 insertions(+), 190 deletions(-) delete mode 100644 app/Latte/AssetFilter.php delete mode 100644 app/Services/Vite.php delete mode 100644 app/Tracy/Vite/Vite.html delete mode 100644 app/Tracy/Vite/Vite.php diff --git a/app/Latte/AssetFilter.php b/app/Latte/AssetFilter.php deleted file mode 100644 index a0cd5f7..0000000 --- a/app/Latte/AssetFilter.php +++ /dev/null @@ -1,21 +0,0 @@ -vite->getAsset($path); - } -} diff --git a/app/Presenters/BasePresenter.php b/app/Presenters/BasePresenter.php index 068c13c..9616604 100644 --- a/app/Presenters/BasePresenter.php +++ b/app/Presenters/BasePresenter.php @@ -13,12 +13,5 @@ */ abstract class BasePresenter extends Nette\Application\UI\Presenter { - public function __construct( - private Vite $vite, - ) {} - public function beforeRender(): void - { - $this->template->vite = $this->vite; - } } diff --git a/app/Services/Vite.php b/app/Services/Vite.php deleted file mode 100644 index 6e921ca..0000000 --- a/app/Services/Vite.php +++ /dev/null @@ -1,91 +0,0 @@ -isEnabled()) { - if (file_exists($this->manifestFile)) { - $manifest = Json::decode(FileSystem::read($this->manifestFile), Json::FORCE_ARRAY); - $asset = $manifest[$entrypoint]['file']; - } else { - trigger_error('Missing manifest file: ' . $this->manifestFile, E_USER_WARNING); - } - - } else { - $baseUrl = $this->viteServer . '/'; - $asset = $entrypoint; - } - - return $baseUrl . $asset; - } - - /** - * @throws \Nette\Utils\JsonException - */ - public function getCssAssets(string $entrypoint): array - { - $assets = []; - - if (!$this->isEnabled()) { - if (file_exists($this->manifestFile)) { - $manifest = Json::decode(FileSystem::read($this->manifestFile), Json::FORCE_ARRAY); - $assets = $manifest[$entrypoint]['css'] ?? []; - } else { - trigger_error('Missing manifest file: ' . $this->manifestFile, E_USER_WARNING); - } - - } - - return $assets; - } - - public function isEnabled(): bool - { - if (!$this->productionMode && $this->httpRequest->getCookie('netteVite') === 'true') { - return true; - } else { - return false; - } - } - - /** - * @throws \Nette\Utils\JsonException - */ - public function printTags(string $entrypoint): void - { - $scripts = [$this->getAsset($entrypoint)]; - $styles = $this->getCssAssets($entrypoint); - - if ($this->isEnabled()) { - echo Html::el('script')->type('module')->src($this->viteServer . '/' . '@vite/client'); - } - - foreach ($styles as $path) { - echo Html::el('link')->rel('stylesheet')->href($path); - } - - foreach ($scripts as $path) { - echo Html::el('script')->type('module')->src($path); - } - } -} diff --git a/app/Tracy/Vite/Vite.html b/app/Tracy/Vite/Vite.html deleted file mode 100644 index 0dd90b0..0000000 --- a/app/Tracy/Vite/Vite.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/app/Tracy/Vite/Vite.php b/app/Tracy/Vite/Vite.php deleted file mode 100644 index 84871cd..0000000 --- a/app/Tracy/Vite/Vite.php +++ /dev/null @@ -1,14 +0,0 @@ - Date: Wed, 15 Jun 2022 08:39:38 +0200 Subject: [PATCH 3/3] used phpstan, autosearch manifest.json, update real path --- .../ManifestFileDoesNotExistsException.php | 8 ++ Vite/src/Nette/Extension.php | 84 ++++++++++++++++--- Vite/src/Service.php | 28 +++++-- Vite/src/Tracy/VitePanel.php | 3 +- Vite/src/ViteToTemplate.php | 13 --- 5 files changed, 101 insertions(+), 35 deletions(-) create mode 100644 Vite/src/ManifestFileDoesNotExistsException.php delete mode 100644 Vite/src/ViteToTemplate.php diff --git a/Vite/src/ManifestFileDoesNotExistsException.php b/Vite/src/ManifestFileDoesNotExistsException.php new file mode 100644 index 0000000..3963c12 --- /dev/null +++ b/Vite/src/ManifestFileDoesNotExistsException.php @@ -0,0 +1,8 @@ + Schema\Expect::string('http://localhost:3000'), 'debugMode' => Schema\Expect::bool($this->getContainerBuilder()->parameters['debugMode'] ?? false), - 'manifestFile' => Schema\Expect::string()->required(), + 'manifestFile' => Schema\Expect::string(), 'filterName' => Schema\Expect::string('asset'), // empty string is for disabled - 'templateProperty' => Schema\Expect::string('_vite'), // empty string is for disabled and you can use ViteToTemplate for Presenter + 'templateProperty' => Schema\Expect::string('_vite'), // empty string is for disabled + 'wwwDir' => Schema\Expect::string($this->getContainerBuilder()->parameters['wwwDir'] ?? getcwd()), + 'basePath' => Schema\Expect::string(), ]); } @@ -35,12 +41,14 @@ public function loadConfiguration(): void private function buildViteService(): void { + $manifestFile = $this->prepareManifestPath(); $this->getContainerBuilder()->addDefinition($this->prefix('service')) ->setFactory(Service::class) ->setArguments([ 'viteServer' => $this->config->server, - 'manifestFile' => $this->config->manifestFile, + 'manifestFile' => $manifestFile, 'debugMode' => $this->config->debugMode, + 'basePath' => $this->prepareBasePath($manifestFile), ]); } @@ -67,13 +75,14 @@ public function beforeCompile(): void self::class, 'prepareTemplate', ], [$this->config->templateProperty, $builder->getDefinition($this->prefix('service'))]), - ]) + ]), ); } if ($this->config->filterName !== '' && $builder->hasDefinition('latte.latteFactory')) { - $builder->getDefinition('latte.latteFactory') - ->getResultDefinition() + $definition = $builder->getDefinition('latte.latteFactory'); + assert($definition instanceof Definitions\FactoryDefinition); + $definition->getResultDefinition() ->addSetup('addFilter', [ $this->config->filterName, $builder->getDefinition($this->prefix('assetFilter')), @@ -82,19 +91,68 @@ public function beforeCompile(): void $tracyClass = Tracy\Bar::class; if ($this->config->debugMode && $builder->getByType($tracyClass)) { - $this->getContainerBuilder()->getDefinition($this->prefix('service')) - ->addSetup("@$tracyClass::addPanel", [ - new Definitions\Statement(VitePanel::class), - ]); + $definition = $this->getContainerBuilder() + ->getDefinition($this->prefix('service')); + assert($definition instanceof Definitions\ServiceDefinition); + $definition->addSetup("@$tracyClass::addPanel", [ + new Definitions\Statement(VitePanel::class), + ]); } } public static function prepareTemplate(string $propertyName, Service $service): \Closure { - return function (Nette\Application\UI\Template $template) use ($propertyName, $service): void { + return static function (Nette\Application\UI\Template $template) use ($propertyName, $service): void { $template->{$propertyName} = $service; }; } + + private function prepareManifestPath(): string + { + if ($this->config->manifestFile === null) { + return $this->automaticSearchManifestFile(); + } + + $manifestFile = $this->config->manifestFile; + if (!is_file($manifestFile)) { + $newPath = $this->config->wwwDir . DIRECTORY_SEPARATOR . ltrim($manifestFile, '/\\'); + if (!is_file($newPath)) { + throw new ManifestFileDoesNotExistsException(sprintf('Found here "%s" or "%s".', $manifestFile, $newPath)); + } + + $manifestFile = $newPath; + } + + return Nette\Safe::realpath($manifestFile); + } + + + private function prepareBasePath(string $manifestFile): string + { + if ($this->config->basePath === null) { + return str_replace(Nette\Safe::realpath($this->config->wwwDir), '', dirname($manifestFile)) . '/'; + } + + return $this->config->basePath; + } + + + private function automaticSearchManifestFile(): string + { + $finder = Nette\Utils\Finder::findFiles('manifest.json')->from($this->config->wwwDir); + $files = []; + foreach ($finder as $file) { + $files[] = $file->getPathname(); + } + if ($files === []) { + throw new ManifestFileDoesNotExistsException(sprintf('Define path to manifest.json, because automatic search found nothing in "%s".', $this->config->wwwDir)); + } elseif (count($files) > 1) { + throw new ManifestFileDoesNotExistsException(sprintf('Define path to manifest.json, because automatic search found many manifest.json files %s.', implode(', ', $files))); + } + + return reset($files); + } + } diff --git a/Vite/src/Service.php b/Vite/src/Service.php index 5dfaf6a..8798fc9 100644 --- a/Vite/src/Service.php +++ b/Vite/src/Service.php @@ -2,10 +2,10 @@ namespace MMEE\Vite; +use Nette\Http\Request; use Nette\Utils\FileSystem; use Nette\Utils\Html; use Nette\Utils\Json; -use Nette\Http\Request; final class Service { @@ -15,39 +15,51 @@ final class Service private bool $debugMode; + private string $basePath; + private Request $httpRequest; - public function __construct(string $viteServer, string $manifestFile, bool $debugMode, Request $httpRequest) + public function __construct( + string $viteServer, + string $manifestFile, + bool $debugMode, + string $basePath, + Request $httpRequest + ) { $this->viteServer = $viteServer; $this->manifestFile = $manifestFile; $this->debugMode = $debugMode; + $this->basePath = $basePath; $this->httpRequest = $httpRequest; } public function getAsset(string $entrypoint): string { - $asset = ''; - $baseUrl = '/'; + if ($this->isEnabled()) { + $baseUrl = $this->viteServer . '/'; + $asset = $entrypoint; + } else { + $baseUrl = $this->basePath; + $asset = ''; - if (!$this->isEnabled()) { if (file_exists($this->manifestFile)) { $manifest = Json::decode(FileSystem::read($this->manifestFile), Json::FORCE_ARRAY); $asset = $manifest[$entrypoint]['file']; } else { trigger_error('Missing manifest file: ' . $this->manifestFile, E_USER_WARNING); } - } else { - $baseUrl = $this->viteServer . '/'; - $asset = $entrypoint; } return $baseUrl . $asset; } + /** + * @return array + */ public function getCssAssets(string $entrypoint): array { $assets = []; diff --git a/Vite/src/Tracy/VitePanel.php b/Vite/src/Tracy/VitePanel.php index 22207f2..522b517 100644 --- a/Vite/src/Tracy/VitePanel.php +++ b/Vite/src/Tracy/VitePanel.php @@ -2,13 +2,14 @@ namespace MMEE\Vite\Tracy; +use Nette\Safe; use Tracy; final class VitePanel implements Tracy\IBarPanel { public function getTab() { - return file_get_contents(__DIR__ . '/Vite.html'); + return Safe::file_get_contents(__DIR__ . '/Vite.html'); } diff --git a/Vite/src/ViteToTemplate.php b/Vite/src/ViteToTemplate.php deleted file mode 100644 index 22f6680..0000000 --- a/Vite/src/ViteToTemplate.php +++ /dev/null @@ -1,13 +0,0 @@ -onRender[] = static fn($presenter) => $presenter->getTemplate()->_vite = $vite; - } - -}