viteHost = $serverConfig->host ?: $this->viteHost;
$this->viteHostProtocol = $serverConfig->protocol ?: $this->viteHostProtocol;
$this->vitePort = $serverConfig->port ?: $this->vitePort;
}
add_filter('script_loader_tag', [$this, 'maybeConvertToModule'], 999, 3);
}
public function maybeConvertToModule($tag, $handle, $src): string
{
$isViteScript = false;
$assetBase = FLUENT_BOARDS_PLUGIN_URL . 'assets/';
if (strpos($src, 'localhost:' . $this->vitePort) !== false || strpos($src, '@vite/client') !== false) {
$isViteScript = true;
}
if (in_array($handle, $this->moduleScripts)) {
$isViteScript = true;
}
if (!$this->shouldServeViaDevServer()) {
$assetPatterns = [
$assetBase . 'admin/',
];
foreach ($assetPatterns as $pattern) {
if (strpos($src, $pattern) !== false && strpos($src, '.js') !== false) {
$excludePatterns = ['/libs/', '/vendor/', 'purify.min.js'];
$isExcluded = false;
foreach ($excludePatterns as $exclude) {
if (strpos($src, $exclude) !== false) {
$isExcluded = true;
break;
}
}
if (!$isExcluded) {
$isViteScript = true;
break;
}
}
}
}
if ($isViteScript) {
if (strpos($tag, 'type="module"') !== false || strpos($tag, "type='module'") !== false) {
return $tag;
}
$tag = preg_replace('/' . "\n";
} else {
$tag = '' . "\n";
}
}
return $tag;
}
private function getFileFromManifest($src)
{
if (isset($this->manifestData[$this->resourceDirectory . $src])) {
return $this->manifestData[$this->resourceDirectory . $src];
}
return '';
}
private function getProductionFilePath($file): string
{
if (!isset($file['file'])) {
return '';
}
$assetPath = static::getAssetPath();
$this->ensureChunkCssIsLoaded($file);
return ($assetPath . $file['file']);
}
private array $mergedIntoStyleCss = [
'admin/vendor.css',
'admin/vendor-element-plus.css',
];
private function ensureChunkCssIsLoaded($file)
{
$assetPath = static::getAssetPath();
$cssFiles = $this->collectChunkCssFiles($file);
foreach ($cssFiles as $cssPath) {
if (isset($this->enqueuedChunkCss[$cssPath])) {
continue;
}
if (in_array($cssPath, $this->mergedIntoStyleCss)) {
$this->enqueuedChunkCss[$cssPath] = true;
continue;
}
wp_enqueue_style(
'fluent_boards_vite_css_' . md5($cssPath),
$assetPath . $cssPath,
[],
FLUENT_BOARDS_PLUGIN_VERSION
);
$this->enqueuedChunkCss[$cssPath] = true;
}
}
private function collectChunkCssFiles($file, &$visited = []): array
{
$cssFiles = [];
if (!is_array($file)) {
return $cssFiles;
}
$fileId = isset($file['file']) ? $file['file'] : md5(wp_json_encode($file));
if (isset($visited[$fileId])) {
return $cssFiles;
}
$visited[$fileId] = true;
if (isset($file['css']) && is_array($file['css'])) {
foreach ($file['css'] as $path) {
if (is_string($path) && $path !== '') {
$cssFiles[] = $path;
}
}
}
if (isset($file['imports']) && is_array($file['imports'])) {
foreach ($file['imports'] as $importKey) {
if (!isset($this->manifestData[$importKey]) || !is_array($this->manifestData[$importKey])) {
continue;
}
$cssFiles = array_merge($cssFiles, $this->collectChunkCssFiles($this->manifestData[$importKey], $visited));
}
}
return array_values(array_unique($cssFiles));
}
public function with($params)
{
if (!is_array($params) || !Arr::isAssoc($params) || empty($this->lastJsHandle)) {
$this->lastJsHandle = null;
return;
}
foreach ($params as $key => $val) {
wp_localize_script($this->lastJsHandle, $key, $val);
}
$this->lastJsHandle = null;
}
public static function enqueueStyle($handle, $src, $dependency = [], $version = null, $media = 'all')
{
static::getInstance()->enqueue_style(
$handle, $src, $dependency, $version, $media
);
}
private function enqueue_style($handle, $src, $dependency = [], $version = null, $media = 'all')
{
if ($this->shouldServeViaDevServer()) {
$srcPath = $this->getVitePath() . $src;
} else {
$assetFile = $this->getFileFromManifest($src);
$srcPath = $this->getProductionFilePath($assetFile);
}
if (empty($srcPath)) {
return;
}
$version = empty($version) ? FLUENT_BOARDS_PLUGIN_VERSION : $version;
wp_enqueue_style($handle, $srcPath, $dependency, $version, $media);
}
public static function enqueueStaticScript($handle, $src, $dependency = [], $version = null, $inFooter = false): Vite
{
$version = empty($version) ? FLUENT_BOARDS_PLUGIN_VERSION : $version;
return static::getInstance()->enqueue_static_script(
$handle, $src, $dependency, $version, $inFooter
);
}
private function enqueue_static_script($handle, $src, $dependency = [], $version = null, $inFooter = false): Vite
{
$version = empty($version) ? FLUENT_BOARDS_PLUGIN_VERSION : $version;
wp_enqueue_script(
$handle,
$this->getStaticEnqueuePath($src),
$dependency,
$version,
$inFooter
);
return $this;
}
private function getStaticEnqueuePath($path): string
{
if ($this->shouldServeViaDevServer()) {
return $this->getVitePath() . $path;
}
return $this->get_asset_url($path);
}
public static function enqueueStaticStyle($handle, $src, $dependency = [], $version = null, $media = 'all')
{
$version = empty($version) ? FLUENT_BOARDS_PLUGIN_VERSION : $version;
static::getInstance()->enqueue_static_style(
$handle, $src, $dependency, $version, $media
);
}
private function enqueue_static_style($handle, $src, $dependency = [], $version = null, $media = 'all')
{
$version = empty($version) ? FLUENT_BOARDS_PLUGIN_VERSION : $version;
wp_enqueue_style(
$handle,
$this->getStaticEnqueuePath($src),
$dependency,
$version,
$media
);
}
public static function underDevelopment(): bool
{
return static::getInstance()->usingDevMode();
}
public function usingDevMode(): bool
{
$app = App::getInstance();
return $app->config->get('app.env') === 'dev';
}
private function shouldServeViaDevServer(): bool
{
return $this->usingDevMode() && $this->isViteServerRunning();
}
private function isViteServerRunning(): bool
{
static $isRunning = null;
if ($isRunning !== null) {
return $isRunning;
}
$viteUrl = $this->viteHostProtocol . $this->viteHost . ':' . $this->vitePort . '/@vite/client';
$response = wp_remote_get($viteUrl, [
'timeout' => 1,
'sslverify' => false
]);
$isRunning = !is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200;
return $isRunning;
}
public function getVitePath(): string
{
$protocol = rtrim($this->viteHostProtocol, ':/');
$host = rtrim($this->viteHost, '/');
$port = $this->vitePort;
$resource = ltrim($this->resourceDirectory, '/');
return sprintf('%s://%s:%s/%s', $protocol, $host, $port, $resource);
}
public static function getAssetUrl($path = ''): string
{
return esc_url(static::getInstance()->get_asset_url($path) ?? '');
}
private function get_asset_url($path = ''): string
{
if ($this->shouldServeViaDevServer()) {
return $this->getVitePath() . $path;
}
return FLUENT_BOARDS_PLUGIN_URL . 'assets/' . ltrim($path, '/');
}
static function getAssetPath(): string
{
return FLUENT_BOARDS_PLUGIN_URL . 'assets/';
}
public static function injectViteClient()
{
$vite = static::getInstance();
if ($vite->shouldServeViaDevServer()) {
$protocol = rtrim($vite->viteHostProtocol, ':/');
$host = rtrim($vite->viteHost, '/');
$port = $vite->vitePort;
$viteClientUrl = sprintf('%s://%s:%s/@vite/client', $protocol, $host, $port);
$handle = 'fluent_boards_vite_client';
if (!in_array($handle, $vite->moduleScripts, true)) {
$vite->moduleScripts[] = $handle;
}
wp_enqueue_script($handle, $viteClientUrl, [], null, false);
}
}
}