benjaminkott / benjaminkott/bootstrap_package
SCSS/JS compilation breaks on TYPO3 v14 for any page.includeCSS/page.includeJS
- Dominant language
- PHP
- Stars
- 355
- Forks
- 212
- Avg merge
- 1h 4m
- Merged PRs (30d)
- 31
Description
SCSS/JS compilation breaks on TYPO3 v14 for any page.includeCSS/page.includeJS entry pointing at fileadmin/... (or other FAL-resolved, non-EXT: paths)
Environment
- bk2k/bootstrap-package: 16.0.0
- typo3/cms-core: v14.3.4
- PHP: 8.4
Summary
On TYPO3 v14, any .scss/.less file referenced in page.includeCSS (or .js in page.includeJS) via a fileadmin-relative path fails to compile with:
ScssPhp\ScssPhp\Exception\CompilerException: `.../public/FAL:1:/templates/demo/theme.scss`
file not found for @import: FAL:1:/templates/demo/theme.scss on line 1, at column 0
EXT:-relative paths (e.g. EXT:bootstrap_package/Resources/Public/Scss/bootstrap5/theme.scss) are unaffected — only paths resolved through TYPO3's file abstraction layer break.
Root cause
In TYPO3 v14, TYPO3\CMS\Frontend\Http\RequestHandler::generatePageContent() no longer passes plain path strings into PageRenderer::addCssFile()/addJsFile(). It now wraps every page.includeCSS/page.includeJS value in a SystemResourceInterface via:
$cssResource = $this->systemResourceFactory->createResource($cssResource);
(vendor/typo3/cms-frontend/Classes/Http/RequestHandler.php, includeCSS handling around line 446)
For anything that isn't an EXT: reference (e.g. a fileadmin/... path), the resultntation used as the PageRenderer cssFiles array key becomes a FAL "combinedidentifier" of the form:
FAL:: e.g. FAL:1:/templates/demo/theme.scss.
BK2K\BootstrapPackage\Hooks\PageRenderer\PreProcessHook::execute() (Classes/Hooksphp:42) takes that array key literally and passes it straight toCompileService::getCompiledFile(), which calls GeneralUtility::getFileAbsFileName($file). That function has no notion of the FAL: notation, so it just prepends the public path to the literal string, producing a bogus path like /var/www/html/public/FAL:1:/templates/demo/thesn't exist, hence the CompilerException.
This affects the extension's own documented usage pattern of per-site/per-mandanteadmin/ (not just custom setups) — any TYPO3 v14 site using a fileadmin-basedtheme.scss convention hits this immediately.
Suggested fix
Resolve the FAL: identifier back to a real filesystem path via ResourceFactory before handing it to CompileService, in PreProcessHook::execute(). Patch attached below — verified against a TYPO3
v14.3.4 + bootstrap-package 16.0.0 site using a fileadmin/templates/{mandant}/theme.scss convention succeeds and the compiled CSS is correct. EXT:-relative entries are untouched since they never start with FAL:.
Patch
--- a/Classes/Hooks/PageRenderer/PreProcessHook.php
+++ b/Classes/Hooks/PageRenderer/PreProcessHook.php
@@ -12,6 +12,7 @@
use BK2K\BootstrapPackage\Service\CompileService;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Http\ApplicationType;
+use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
@@ -39,7 +40,8 @@
$files = [];
if (is_array($params[$key])) {
foreach ($params[$key] as $file => $settings) {
- $compiledFile = $this->getCompileService()->getCompiledFile($GLOBALS['TYPO3_REQUEST'], $file);
+ $resolvedFile = $this->resolveFalIdentifier($file);
+ $compiledFile = $this->getCompileService()->getCompiledFile($GLOBALS['TYPO3_REQUEST'], $resolvedFile);
if ($compiledFile !== null) {
$settings['file'] = $compiledFile;
$files[$compiledFile] = $settings;
@@ -53,6 +55,33 @@
}
/**
+ * TYPO3 >= 14 wraps page.includeCSS/includeJS values that point at fileadmin (or
+ * other non-EXT:) files in a SystemResource object before this hook ever se
+ * the array key we receive is then its string representation, e.g.
+ * "FAL:1:/templates/demo/theme.scss", which GeneralUtility::getFileAbsFileN
+ * cannot resolve. Resolve it back to a real filesystem path via FAL so the SCSS
+ * compiler can find the file. EXT:-relative values are untouched (unaffecte
+ *
+ * @param string $file
+ * @return string
+ */
+ protected function resolveFalIdentifier(string $file): string
+ {
+ if (str_starts_with($file, 'FAL:')) {
+ try {
+ $fileObject = GeneralUtility::makeInstance(ResourceFactory::class)
+ ->getFileObjectFromCombinedIdentifier(substr($file, 4));
+ if ($fileObject !== null) {
+ return $fileObject->getForLocalProcessing(false);
+ }
+ } catch (\Throwable) {
+ // fall through and let the caller deal with the original value
+ }
+ }
+ return $file;
+ }
+
+ /**
* Get the compile service
*
* @return CompileService
---
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with Classes/Hooks/PageRenderer/PreProcessHook.php and the TYPO3 v14 RequestHandler includeCSS/includeJS handling around line 446. Reproduce the fileadmin-based SCSS or JS case described in the issue, then verify that FAL-resolved assets compile successfully while EXT:-relative entries remain unaffected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, php, scss
- Domain
- build-system, frontend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100