benjaminkott / benjaminkott/bootstrap_package

SCSS/JS compilation breaks on TYPO3 v14 for any page.includeCSS/page.includeJS

Open Beginner friendly
#1,632 0 comments 0 reactions 0 assignees View on GitHub
bug
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.