Custom css or js proccessor in TYPO3

Short background of problem which pointed me into this feature.

We had decided in our project to focus more on seo and speed testing. All went great, mostly for desktop devices. All images were optimalized on their sizes and also webp format was used. Desktop reached 100% in speedtest, but for mobile I wasn’t able to across 80%. The reason was too large css file (300KB). It is the whole, not cleaned tailwind. In the css file are included all media queries. So I got an idea how to speed up mobile integration: Split css file into separated files for every media query. The result was interesting. The amount of downloaded data was still 300KB, but in parallel 50KB packages and the first mobile interaction waits just for the one 50KB package, the rest is for larger screens. This solution gave me new 10 points, so I was finally on 90% for mobile.

How to create custom css / js parser in TYPO3?

All we need are just two files. Sounds easy, right?

First is config file ext_localconf.php


if (TYPO3_MODE === 'FE') {
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess']['seospeed'] = \Vendor\ExtName\Hooks\RenderPreProcessorHook::class . '->renderPreProcessorProc';
}

We can see what will come now from the configuration.

Classes/Hooks/RenderPreProcessorHook.php

<?php

namespace Vendor\ExtName\Hooks;

use TYPO3\CMS\Core\Page\PageRenderer;

class RenderPreProcessorHook
{
    /**
     * Main hook function
     *
     * @param array $params Array of CSS/javascript and other files
     * @param PageRenderer $pagerenderer Pagerenderer object
     * @return void
     * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
     * @throws \TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
     * @throws \TYPO3\CMS\Core\Resource\Exception\InvalidFileException
     * @throws \TYPO3\CMS\Core\Resource\Exception\InvalidFileNameException
     * @throws \TYPO3\CMS\Core\Resource\Exception\InvalidPathException
     */
    public function renderPreProcessorProc(&$params, PageRenderer $pagerenderer)
    {
        if (!\is_array($params['cssFiles'])) {
            return;
        }

        $cssFiles = [];
        foreach ($params['cssFiles'] as $file => $conf) {
            
            // Do your stuff with the file, add new files, remove some of them etc.
            // This example replace fileadmin/test.css from typoscript into EXT:my_ext/Resources/Public/Css/MyStyle.css
            if ($file == 'fileadmin/test.css') {
                $cssFiles[$file] = [
                     'file' => 'EXT:my_ext/Resources/Public/Css/MyStyle.css',
                     'rel' => 'stylesheet',
                     'media' => 'all',
                     'title' => '',
                     'compress' => true,
                     'forceOnTop' => true,
                     'allWrap' => NULL, 
                     'excludeFromConcatenation' => true,
                     'splitChar' => NULL,
                     'inline' => NULL
                 ]; 
             }
        }
        $params['cssFiles'] = array_merge($params['cssFiles'], $cssFiles);
    }
}