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/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(), + 'filterName' => Schema\Expect::string('asset'), // empty string is for disabled + 'templateProperty' => Schema\Expect::string('_vite'), // empty string is for disabled + 'wwwDir' => Schema\Expect::string($this->getContainerBuilder()->parameters['wwwDir'] ?? getcwd()), + 'basePath' => Schema\Expect::string(), + ]); + } + + + public function loadConfiguration(): void + { + $this->buildViteService(); + $this->buildFilter(); + } + + + private function buildViteService(): void + { + $manifestFile = $this->prepareManifestPath(); + $this->getContainerBuilder()->addDefinition($this->prefix('service')) + ->setFactory(Service::class) + ->setArguments([ + 'viteServer' => $this->config->server, + 'manifestFile' => $manifestFile, + 'debugMode' => $this->config->debugMode, + 'basePath' => $this->prepareBasePath($manifestFile), + ]); + } + + + 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')) { + $definition = $builder->getDefinition('latte.latteFactory'); + assert($definition instanceof Definitions\FactoryDefinition); + $definition->getResultDefinition() + ->addSetup('addFilter', [ + $this->config->filterName, + $builder->getDefinition($this->prefix('assetFilter')), + ]); + } + + $tracyClass = Tracy\Bar::class; + if ($this->config->debugMode && $builder->getByType($tracyClass)) { + $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 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 new file mode 100644 index 0000000..8798fc9 --- /dev/null +++ b/Vite/src/Service.php @@ -0,0 +1,104 @@ +viteServer = $viteServer; + $this->manifestFile = $manifestFile; + $this->debugMode = $debugMode; + $this->basePath = $basePath; + $this->httpRequest = $httpRequest; + } + + + public function getAsset(string $entrypoint): string + { + if ($this->isEnabled()) { + $baseUrl = $this->viteServer . '/'; + $asset = $entrypoint; + } else { + $baseUrl = $this->basePath; + $asset = ''; + + 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); + } + } + + return $baseUrl . $asset; + } + + + /** + * @return array + */ + 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/app/Tracy/Vite/Vite.html b/Vite/src/Tracy/Vite.html similarity index 98% rename from app/Tracy/Vite/Vite.html rename to Vite/src/Tracy/Vite.html index 0dd90b0..00d3543 100644 --- a/app/Tracy/Vite/Vite.html +++ b/Vite/src/Tracy/Vite.html @@ -34,8 +34,6 @@ const element = document.querySelector('#tracy-debug [data-action="netteVite"]') - console.log(getCookie('netteVite')) - if (!getCookie('netteVite')) { element.style.opacity = '40%' } diff --git a/Vite/src/Tracy/VitePanel.php b/Vite/src/Tracy/VitePanel.php new file mode 100644 index 0000000..522b517 --- /dev/null +++ b/Vite/src/Tracy/VitePanel.php @@ -0,0 +1,21 @@ +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.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 @@ -