dimti
2 years ago
11 changed files with 402 additions and 78 deletions
-
24Plugin.php
-
14README.md
-
2classes/ManifestReader.php
-
77classes/TwigFilters.php
-
45classes/bundlers/Bundler.php
-
166classes/bundlers/ViteBundler.php
-
6classes/bundlers/WebpackEncoreBundler.php
-
72classes/bundlers/vite/ViteEntrypoint.php
-
61components/Manifest.php
-
3components/manifest/default.htm
-
10config/config.php
@ -0,0 +1,14 @@ |
|||||
|
# Env file example |
||||
|
|
||||
|
## Vitejs |
||||
|
```bash |
||||
|
VITE_DEV_SERVER_PROTOCOL=http |
||||
|
VITE_DEV_SERVER_HOST=localhost |
||||
|
VITE_DEV_SERVER_PORT=3000 |
||||
|
|
||||
|
VITE_PATH_SRC=assets/src |
||||
|
VITE_DIR_ENTRYPOINTS=entrypoints |
||||
|
VITE_PATH_BUILD=assets/build |
||||
|
VITE_ENTRYPOINTS_FILE=entrypoints.json |
||||
|
VITE_DEV_ENABLED=true |
||||
|
``` |
@ -0,0 +1,45 @@ |
|||||
|
<?php namespace Wpstudio\AssetsManifest\Classes\Bundlers; |
||||
|
|
||||
|
use Wpstudio\AssetsManifest\Classes\AssetsManifestException; |
||||
|
use Wpstudio\AssetsManifest\Classes\ManifestReader; |
||||
|
|
||||
|
abstract class Bundler |
||||
|
{ |
||||
|
const BUNDLER_WEBPACK_ENCORE = 'webpack-encore'; |
||||
|
const BUNDLER_VITE = 'vite'; |
||||
|
|
||||
|
public static array $bundlers = [ |
||||
|
self::BUNDLER_WEBPACK_ENCORE => WebpackEncoreBundler::class, |
||||
|
self::BUNDLER_VITE => ViteBundler::class, |
||||
|
]; |
||||
|
|
||||
|
protected ManifestReader $manifestReader; |
||||
|
|
||||
|
public function __construct(ManifestReader $manifestReader) |
||||
|
{ |
||||
|
$this->manifestReader = $manifestReader; |
||||
|
} |
||||
|
|
||||
|
public function getBundlerType(): string |
||||
|
{ |
||||
|
return array_flip(self::$bundlers)[get_class($this)]; |
||||
|
} |
||||
|
|
||||
|
public function validateBundlerType(string $bundlerType) |
||||
|
{ |
||||
|
if ($this->getBundlerType() != $bundlerType) { |
||||
|
throw new AssetsManifestException( |
||||
|
sprintf( |
||||
|
'Expected bundler type is %s, but actual %s', |
||||
|
$bundlerType, |
||||
|
$this->getBundlerType() |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public function getEntrypoint(string $entrypointPathInManifest): array |
||||
|
{ |
||||
|
return $this->manifestReader->get($entrypointPathInManifest); |
||||
|
} |
||||
|
} |
@ -0,0 +1,166 @@ |
|||||
|
<?php namespace Wpstudio\AssetsManifest\Classes\Bundlers; |
||||
|
|
||||
|
use Cms\Classes\Theme; |
||||
|
use Illuminate\Support\Collection; |
||||
|
use Wpstudio\AssetsManifest\Classes\AssetsManifestException; |
||||
|
use Config; |
||||
|
use Wpstudio\AssetsManifest\Classes\Bundlers\Vite\ViteEntrypoint; |
||||
|
|
||||
|
class ViteBundler extends Bundler |
||||
|
{ |
||||
|
private array $assetsInjected = []; |
||||
|
|
||||
|
public function getEntrypointAssets(string $entrypointName): string |
||||
|
{ |
||||
|
$entrypoint = $this->getViteEntrypoint($entrypointName); |
||||
|
|
||||
|
$tags = collect(); |
||||
|
|
||||
|
if ($entrypoint->hasImports()) { |
||||
|
$entrypoint->getImports()->filter(fn(string $entrypointNameFromImports) => !$this->hasInjected($entrypointNameFromImports))->each( |
||||
|
fn(string $entrypointNameFromImports) => $this->injectAsset( |
||||
|
$entrypointNameFromImports, |
||||
|
$tags, |
||||
|
$this->getEntrypointAssets($entrypointNameFromImports) |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
if ($entrypoint->hasCss()) { |
||||
|
$entrypoint->getCss()->filter(fn(string $cssAssetRelativeFilePath) => !$this->hasInjected($cssAssetRelativeFilePath))->each( |
||||
|
fn(string $cssAssetRelativeFilePath) => $this->injectAsset( |
||||
|
$cssAssetRelativeFilePath, |
||||
|
$tags, |
||||
|
$this->getStylesheetTag($this->getViteAssetUrl($cssAssetRelativeFilePath)) |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
if (!$this->hasInjected($entrypointName)) { |
||||
|
$this->injectAsset($entrypointName, $tags, $this->getScriptTag($entrypointName, $entrypoint)); |
||||
|
} |
||||
|
|
||||
|
return $tags->implode(PHP_EOL); |
||||
|
} |
||||
|
|
||||
|
public function getViteDevClientScriptTag(): string |
||||
|
{ |
||||
|
return sprintf( |
||||
|
'<script type="module" src="%s"></script>', |
||||
|
sprintf( |
||||
|
'%s/@vite/client', |
||||
|
$this->getViteDevServerAddress(), |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param string $entrypointName |
||||
|
* @return string |
||||
|
* @throws AssetsManifestException |
||||
|
*/ |
||||
|
public function getEntrypointStylesheets(string $entrypointName): string |
||||
|
{ |
||||
|
if ($this->isViteDevEnabled()) { |
||||
|
return ''; |
||||
|
} |
||||
|
|
||||
|
$entrypoint = $this->getViteEntrypoint($entrypointName); |
||||
|
|
||||
|
$stylesheetTags = collect(); |
||||
|
|
||||
|
if ($entrypoint->hasCss()) { |
||||
|
$entrypoint |
||||
|
->getCss() |
||||
|
->filter(fn(string $cssAssetRelativeFilePath) => !$this->hasInjected($cssAssetRelativeFilePath)) |
||||
|
->each( |
||||
|
fn(string $cssAssetRelativeFilePath) => $this->injectAsset( |
||||
|
$cssAssetRelativeFilePath, |
||||
|
$stylesheetTags, |
||||
|
$this->getStylesheetTag($this->getViteAssetUrl($cssAssetRelativeFilePath) |
||||
|
) |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
return $stylesheetTags->implode(PHP_EOL); |
||||
|
} |
||||
|
|
||||
|
private function getStylesheetTag(string $href): string |
||||
|
{ |
||||
|
return sprintf( |
||||
|
'<link rel="stylesheet" href="%s">', |
||||
|
$href, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private function getScriptTag(string $entrypointName, ViteEntrypoint $entrypoint): string |
||||
|
{ |
||||
|
return sprintf( |
||||
|
'<script type="module" src="%s" %s></script>', |
||||
|
$this->isViteDevEnabled() ? |
||||
|
sprintf( |
||||
|
'%s/%s', |
||||
|
$this->getViteDevServerAddress(), |
||||
|
$this->getViteEntrypointSrc($entrypointName) |
||||
|
) : |
||||
|
$this->getViteAssetUrl($entrypoint->getFile()), |
||||
|
!$this->isViteDevEnabled() ? 'async defer' : '', |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private function getViteEntrypointSrc(string $entrypointName): string |
||||
|
{ |
||||
|
return sprintf( |
||||
|
'%s/%s/%s', |
||||
|
Config::get('wpstudio.assetsmanifest::vite_path_src'), |
||||
|
Config::get('wpstudio.assetsmanifest::vite_dir_entrypoints'), |
||||
|
$entrypointName, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private function getViteEntrypoint(string $entrypointName): ViteEntrypoint |
||||
|
{ |
||||
|
return new ViteEntrypoint($this->getEntrypoint( |
||||
|
!starts_with($entrypointName, '_') ? |
||||
|
$this->getViteEntrypointSrc($entrypointName) : |
||||
|
$entrypointName |
||||
|
)); |
||||
|
} |
||||
|
|
||||
|
private function getViteAssetUrl(string $relativeAssetsFilePath): string |
||||
|
{ |
||||
|
return sprintf( |
||||
|
'/themes/%s/%s/%s', |
||||
|
Theme::getActiveTheme()->getDirName(), |
||||
|
Config::get('wpstudio.assetsmanifest::vite_path_build'), |
||||
|
$relativeAssetsFilePath |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public function isViteDevEnabled(): bool |
||||
|
{ |
||||
|
return Config::get('wpstudio.assetsmanifest::vite_dev_enabled'); |
||||
|
} |
||||
|
|
||||
|
private function getViteDevServerAddress(): string |
||||
|
{ |
||||
|
return sprintf( |
||||
|
'%s://%s:%s', |
||||
|
Config::get('wpstudio.assetsmanifest::vite_dev_server_protocol'), |
||||
|
Config::get('wpstudio.assetsmanifest::vite_dev_server_host'), |
||||
|
Config::get('wpstudio.assetsmanifest::vite_dev_server_port'), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private function hasInjected(string $assetsUid): bool |
||||
|
{ |
||||
|
return in_array($assetsUid, $this->assetsInjected); |
||||
|
} |
||||
|
|
||||
|
private function injectAsset(string $assetsUid, Collection $tags, string $assetTag): void |
||||
|
{ |
||||
|
$this->assetsInjected[] = $assetsUid; |
||||
|
|
||||
|
$tags->add($assetTag); |
||||
|
} |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
<?php namespace Wpstudio\AssetsManifest\Classes\Bundlers; |
||||
|
|
||||
|
class WebpackEncoreBundler extends Bundler |
||||
|
{ |
||||
|
|
||||
|
} |
@ -0,0 +1,72 @@ |
|||||
|
<?php namespace Wpstudio\AssetsManifest\Classes\Bundlers\Vite; |
||||
|
|
||||
|
use Illuminate\Support\Collection; |
||||
|
|
||||
|
class ViteEntrypoint |
||||
|
{ |
||||
|
public string $file; |
||||
|
public ?string $src; |
||||
|
public ?bool $isEntry; |
||||
|
public ?Collection $imports; |
||||
|
public ?Collection $css; |
||||
|
|
||||
|
public function __construct(array $entrypoint) |
||||
|
{ |
||||
|
$this->file = $entrypoint['file']; |
||||
|
|
||||
|
if (array_key_exists('src', $entrypoint)) { |
||||
|
$this->isEntry = $entrypoint['src']; |
||||
|
} |
||||
|
|
||||
|
if (array_key_exists('isEntry', $entrypoint)) { |
||||
|
$this->isEntry = $entrypoint['isEntry']; |
||||
|
} |
||||
|
|
||||
|
if (array_key_exists('imports', $entrypoint)) { |
||||
|
$this->imports = collect($entrypoint['imports']); |
||||
|
} |
||||
|
|
||||
|
if (array_key_exists('css', $entrypoint)) { |
||||
|
$this->css = collect($entrypoint['css']); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public function getIsEntry(): bool |
||||
|
{ |
||||
|
if (isset($this->isEntry) && $this->isEntry) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public function hasImports() |
||||
|
{ |
||||
|
return isset($this->imports) && $this->imports; |
||||
|
} |
||||
|
|
||||
|
public function getImports(): Collection |
||||
|
{ |
||||
|
return $this->imports; |
||||
|
} |
||||
|
|
||||
|
public function hasCss() |
||||
|
{ |
||||
|
return isset($this->css) && $this->css; |
||||
|
} |
||||
|
|
||||
|
public function getCss(): Collection |
||||
|
{ |
||||
|
return $this->css; |
||||
|
} |
||||
|
|
||||
|
public function getFile(): string |
||||
|
{ |
||||
|
return $this->file; |
||||
|
} |
||||
|
|
||||
|
public function getSrc(): string |
||||
|
{ |
||||
|
return $this->src; |
||||
|
} |
||||
|
} |
@ -1,61 +0,0 @@ |
|||||
<?php namespace Wpstudio\Assetsmanifest\Components; |
|
||||
|
|
||||
use Cms\Classes\ComponentBase; |
|
||||
use Cms\Classes\Theme; |
|
||||
use Wpstudio\AssetsManifest\Classes\ManifestReader; |
|
||||
|
|
||||
class Manifest extends ComponentBase |
|
||||
{ |
|
||||
const LANG_PREFIX = 'wpstudio.assetsmanifest::lang.components.manifest.'; |
|
||||
|
|
||||
private ?ManifestReader $manifestReader; |
|
||||
|
|
||||
public function componentDetails(): array |
|
||||
{ |
|
||||
return [ |
|
||||
'name' => self::LANG_PREFIX . 'name', |
|
||||
'description' => self::LANG_PREFIX . 'description', |
|
||||
]; |
|
||||
} |
|
||||
|
|
||||
public function defineProperties(): array |
|
||||
{ |
|
||||
return [ |
|
||||
'path' => [ |
|
||||
'title' => self::LANG_PREFIX . 'properties.path.title', |
|
||||
'description' => self::LANG_PREFIX . 'properties.path.description', |
|
||||
'validationPattern' => '^[^/].*/manifest.json', |
|
||||
'validationMessage' => self::LANG_PREFIX . 'properties.path.validationMessage', |
|
||||
'placeholder' => 'assets/build/manifest.json', |
|
||||
'default' => 'assets/build/manifest.json', |
|
||||
'showExternalParam' => false, |
|
||||
'required' => true, |
|
||||
] |
|
||||
]; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* @return void |
|
||||
* @throws \Wpstudio\AssetsManifest\Classes\AssetsManifestException |
|
||||
*/ |
|
||||
public function init(): void |
|
||||
{ |
|
||||
app()->instance(Manifest::class, $this); |
|
||||
|
|
||||
$this->prepareVars(); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* @return void |
|
||||
* @throws \Wpstudio\AssetsManifest\Classes\AssetsManifestException |
|
||||
*/ |
|
||||
private function prepareVars(): void |
|
||||
{ |
|
||||
$this->manifestReader = new ManifestReader(Theme::getActiveTheme()->getPath() . '/' . $this->property('path')); |
|
||||
} |
|
||||
|
|
||||
public function getManifestReader(): ManifestReader |
|
||||
{ |
|
||||
return $this->manifestReader; |
|
||||
} |
|
||||
} |
|
@ -1,3 +0,0 @@ |
|||||
<p>This is the default markup for component manifest</p> |
|
||||
|
|
||||
<small>You can delete this file if you want</small> |
|
@ -0,0 +1,10 @@ |
|||||
|
<?php return [ |
||||
|
'vite_dev_enabled' => env('VITE_DEV_ENABLED', true), |
||||
|
'vite_dev_server_protocol' => env('VITE_DEV_SERVER_PROTOCOL', 'http'), |
||||
|
'vite_dev_server_host' => env('VITE_DEV_SERVER_HOST', 'localhost'), |
||||
|
'vite_dev_server_port' => env('VITE_DEV_SERVER_PORT', '3000'), |
||||
|
'vite_path_src' => env('VITE_PATH_SRC', 'assets/src'), |
||||
|
'vite_dir_entrypoints' => env('VITE_DIR_ENTRYPOINTS', 'entrypoints'), |
||||
|
'vite_path_build' => env('VITE_PATH_BUILD', 'assets/build'), |
||||
|
'bundler' => \Wpstudio\AssetsManifest\Classes\Bundlers\ViteBundler::class |
||||
|
]; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue