Magento has published a patch for this for Magento 2.4.5: "ACSD-46815: static content deploy fails when using compact strategy".
The ACSD-46815 patch fixes the issue where the static content deployment fails when the compact strategy is used. This patch is available when the Quality Patches Tool (QPT) 1.1.20 is installed.
Read more about this patch at
https://experienceleague.adobe.com/docs/commerce-knowledge-base/kb/support-tools/patches/v1-1-20/acsd-46815-static-content-deploy-fails-when-using-compact-strategy.html
Possibly, you can also apply the patch via composer, here is the patch file content
https://github.com/magento/quality-patches/blob/master/patches/os/ACSD-46815_2.4.5_v2.patch
As for Magento 2.4.4, I've written a patch for this issue:
diff --git a/vendor/magento/module-deploy/Collector/Collector.php b/vendor/magento/module-deploy/Collector/Collector.php
index b09001a7ac04..441d165f6792 100644
--- a/vendor/magento/module-deploy/Collector/Collector.php
+++ b/vendor/magento/module-deploy/Collector/Collector.php
@@ -93,6 +93,9 @@ public function collect()
if ($file->getModule() && !$this->moduleManager->isEnabled($file->getModule())) {
continue;
}
+ if (!$file->getFileName()) {
+ continue;
+ }
$file->setDeployedFileName($this->fileNameResolver->resolve($file->getFileName()));
$params = $this->getParams($file);
$packagePath = "{$params['area']}/{$params['theme']}/{$params['locale']}";
diff --git a/vendor/magento/module-deploy/Package/Processor/PreProcessor/Css.php b/vendor/magento/module-deploy/Package/Processor/PreProcessor/Css.php
index 152c95f86552..6fc9c05eb352 100644
--- a/vendor/magento/module-deploy/Package/Processor/PreProcessor/Css.php
+++ b/vendor/magento/module-deploy/Package/Processor/PreProcessor/Css.php
@@ -120,6 +120,20 @@ private function hasOverrides(PackageFile $parentFile, Package $package)
return false;
}
+ /**
+ * See if given path is local or remote URL
+ *
+ * @param string $path
+ * @return bool
+ */
+ private function isLocal(string $path): bool
+ {
+ $pattern = '{^(file://(?!//)|/(?!/)|/?[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i';
+ $result = preg_match($pattern, $path);
+
+ return is_int($result) ? (bool) $result : true;
+ }
+
/**
* Build map file
*
@@ -135,13 +149,22 @@ private function buildMap($packagePath, $filePath, $fullPath)
$imports = [];
$this->map[$fullPath] = [];
- $content = $this->staticDir->readFile($this->minification->addMinifiedSign($fullPath));
+ $tmpFilename = $this->minification->addMinifiedSign($fullPath);
+ if ($this->staticDir->isReadable($tmpFilename)) {
+ $content = $this->staticDir->readFile($tmpFilename);
+ } else {
+ $content = '';
+ }
$callback = function ($matchContent) use ($packagePath, $filePath, &$imports) {
- $importRelPath = $this->normalize(pathinfo($filePath, PATHINFO_DIRNAME) . '/' . $matchContent['path']);
- $imports[$importRelPath] = $this->normalize(
- $packagePath . '/' . pathinfo($filePath, PATHINFO_DIRNAME) . '/' . $matchContent['path']
- );
+ if ($this->isLocal($matchContent['path'])) {
+ $importRelPath = $this->normalize(
+ pathinfo($filePath, PATHINFO_DIRNAME) . '/' . $matchContent['path']
+ );
+ $imports[$importRelPath] = $this->normalize(
+ $packagePath . '/' . pathinfo($filePath, PATHINFO_DIRNAME) . '/' . $matchContent['path']
+ );
+ }
};
preg_replace_callback(Import::REPLACE_PATTERN, $callback, $content);
diff --git a/vendor/magento/module-deploy/Package/Processor/PreProcessor/Less.php b/vendor/magento/module-deploy/Package/Processor/PreProcessor/Less.php
index dbda66cc948f..f4339b40f5be 100644
--- a/vendor/magento/module-deploy/Package/Processor/PreProcessor/Less.php
+++ b/vendor/magento/module-deploy/Package/Processor/PreProcessor/Less.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Deploy\Package\Processor\PreProcessor;
use Magento\Deploy\Console\DeployStaticOptions;
@@ -10,10 +11,10 @@ use Magento\Deploy\Package\Package;
use Magento\Deploy\Package\PackageFile;
use Magento\Deploy\Package\Processor\ProcessorInterface;
use Magento\Deploy\Service\DeployStaticFile;
-use Magento\Framework\View\Asset\PreProcessor\FileNameResolver;
-use Magento\Framework\View\Asset\Minification;
use Magento\Framework\Css\PreProcessor\Instruction\Import;
+use Magento\Framework\View\Asset\Minification;
use Magento\Framework\View\Asset\NotationResolver;
+use Magento\Framework\View\Asset\PreProcessor\FileNameResolver;
use Magento\Framework\View\Asset\Repository;
/**
@@ -58,6 +59,11 @@ class Less implements ProcessorInterface
*/
private $map = [];
+ /**
+ * @var array
+ */
+ private $pFileCache = [];
+
/**
* Less constructor
*
@@ -67,10 +73,10 @@ class Less implements ProcessorInterface
* @param Minification $minification
*/
public function __construct(
- FileNameResolver $fileNameResolver,
+ FileNameResolver $fileNameResolver,
NotationResolver\Module $notationResolver,
- DeployStaticFile $deployStaticFile,
- Minification $minification
+ DeployStaticFile $deployStaticFile,
+ Minification $minification
) {
$this->fileNameResolver = $fileNameResolver;
$this->notationResolver = $notationResolver;
@@ -94,7 +100,7 @@ class Less implements ProcessorInterface
if ($packageFile && $packageFile->getOrigPackage() === $package) {
continue;
}
- $deployFileName = $this->fileNameResolver->resolve($file->getFileName());
+ $deployFileName = $this->fileNameResolver->resolve($file->getFileName() ?? '');
if ($deployFileName !== $file->getFileName()) {
if ($this->hasOverrides($file, $package)) {
$file = clone $file;
@@ -131,6 +137,7 @@ class Less implements ProcessorInterface
$currentPackageFiles = array_merge($package->getFilesByType('less'), $package->getFilesByType('css'));
foreach ($currentPackageFiles as $file) {
+ $this->pFileCache = [];
if ($this->inParentFiles($file->getDeployedFileName(), $parentFile->getFileName(), $map)) {
return true;
}
@@ -139,8 +146,10 @@ class Less implements ProcessorInterface
}
/**
- * @param string $fileName
- * @param string $parentFile
+ * Checks if there is a LESS file in current package which used for generating given CSS from parent package
+ *
+ * @param string $fileName
+ * @param string $parentFile
* @param array $map
* @return bool
*/
@@ -151,7 +160,13 @@ class Less implements ProcessorInterface
return true;
} else {
foreach ($map[$parentFile] as $pFile) {
- return $this->inParentFiles($fileName, $pFile, $map);
+ if (in_array($pFile, $this->pFileCache)) {
+ continue;
+ }
+ $this->pFileCache[] = $pFile;
+ if ($this->inParentFiles($fileName, $pFile, $map)) {
+ return true;
+ }
}
}
}
@@ -170,13 +185,15 @@ class Less implements ProcessorInterface
{
$content = $this->deployStaticFile->readTmpFile($filePath, $packagePath);
$replaceCallback = function ($matchedContent) use ($filePath, $packagePath, $contentType) {
- $matchedFileId = $matchedContent['path'];
+ $matchedFileId = $matchedContent['path'] ?? '';
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
if (!pathinfo($matchedContent['path'], PATHINFO_EXTENSION)) {
$matchedFileId .= '.' . $contentType;
}
if (strpos($matchedFileId, Repository::FILE_ID_SEPARATOR) !== false) {
$basePath = $packagePath;
} else {
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
$basePath = pathinfo($filePath, PATHINFO_DIRNAME);
}
$resolvedPath = str_replace(Repository::FILE_ID_SEPARATOR, '/', $matchedFileId);
@@ -205,7 +222,7 @@ class Less implements ProcessorInterface
*/
private function normalizePath($path)
{
- if (strpos($path, '/../') === false) {
+ if ($path === null || strpos($path, '/../') === false) {
return $path;
}
$pathParts = explode('/', $path);