PHPackages                             maispace/assets - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. maispace/assets

ActiveTypo3-cms-extension

maispace/assets
===============

Easy inline or path-based asset inclusion (CSS, JS, SCSS) from Fluid templates. Performance-focused: minification, deferred loading, caching, and SVG sprite building.

v13.1.0(2mo ago)0210GPL-2.0-or-laterPHPPHP ^8.2CI failing

Since Feb 28Pushed 1mo agoCompare

[ Source](https://github.com/mai-space-de/typo3-extension-assets)[ Packagist](https://packagist.org/packages/maispace/assets)[ RSS](/packages/maispace-assets/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (10)Versions (5)Used By (0)

maispace/assets — TYPO3 Asset ViewHelpers
=========================================

[](#maispaceassets--typo3-asset-viewhelpers)

[![CI](https://github.com/mai-space-de/typo3-extension-assets/actions/workflows/ci.yml/badge.svg)](https://github.com/mai-space-de/typo3-extension-assets/actions/workflows/ci.yml)[![PHP](https://camo.githubusercontent.com/187240af044d09d5b14a1d9d9ebdf3f7a993e4c7bc09bdb46b4ba661a891bf5b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d626c7565)](https://www.php.net/)[![TYPO3](https://camo.githubusercontent.com/8e07c24b7f613f6d30d4836b4d39c2b1722b1f030602202a878615f2d6cf25fa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5459504f332d31332e342532304c54532d6f72616e6765)](https://typo3.org/)[![License: GPL v2](https://camo.githubusercontent.com/77e900ae34f8da9ccccc42662fce61a94ab07ddbfe3f7d066178e824f3673dbd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d47504c25323076322d626c75652e737667)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)

A TYPO3 extension that provides Fluid ViewHelpers for CSS, JavaScript, SCSS, images, SVG sprites, Lottie animations, and web font preloading — all from Fluid templates, with performance-first defaults.

**Requires:** TYPO3 13.4 LTS · PHP 8.2+

---

Features at a glance
--------------------

[](#features-at-a-glance)

FeatureViewHelper / APICSS from file, inline, or external URL``JavaScript from file, inline, or external URL``SCSS compiled server-side (no Node.js)``Import maps (JSON unmangled, always synchronous)``Legacy bundle differential loading``Resource hints (preconnect, dns-prefetch, modulepreload, preload…)``Responsive `` with lazy load, preload, srcset, decoding, crossorigin``Responsive `` with per-breakpoint sources, srcset, quality`` + ``Automatic WebP/AVIF `` sets in ```formats="avif, webp"` or `image.alternativeFormats`Global image format conversion (WebP/AVIF)`image.forceFormat` TypoScript / `fileExtension` argumentLottie animations via `` web component``Inline SVG embedding from file (CSS/JS accessible)``SVG sprite served from a cacheable URL`` + `Configuration/SpriteIcons.php`Web font `` in ```Configuration/Fonts.php`CSP nonce on inline `` / ```nonce` argument (auto-detected from TYPO3 request)SRI integrity on local assets`integrity="true"` argumentSRI integrity on external assets`integrityValue="sha384-..."` argumentSemantic `/` wrapper``Multi-site scoping for sprites and fonts`'sites'` key in config filesCritical CSS extraction &amp; inlining`maispace:assets:critical:extract`Deploy-time cache warm-up`php vendor/bin/typo3 maispace:assets:warmup`PSR-14 events at every processing stage`Classes/Event/`Brotli + gzip pre-compressed CSS/JS static files`compression.enable` / `compression.brotli` / `compression.gzip`Runtime-compressed SVG sprite (Brotli → gzip → plain)`SvgSpriteMiddleware`---

Installation
------------

[](#installation)

```
composer require maispace/assets
```

Include the TypoScript setup in your site package:

```
@import 'EXT:maispace_assets/Configuration/TypoScript/setup.typoscript'

```

No extension manager configuration, no ext\_tables.php boilerplate.

---

CSS &amp; JavaScript
--------------------

[](#css--javascript)

Include assets inline or from a file. Local assets are minified, cached in `typo3temp/`, and registered with TYPO3's AssetCollector. External URLs are passed through directly — no local copy is made.

```

    body { margin: 0; font-family: sans-serif; }

```

### Import maps

[](#import-maps)

Import maps must be inline JSON and must load synchronously before any `type="module"` script. The ViewHelper enforces this automatically: no minification, no `defer`, always placed in ``.

```

{
    "imports": {
        "lodash": "/node_modules/lodash-es/lodash.js",
        "app": "/assets/app.js"
    }
}

```

---

SCSS
----

[](#scss)

Compile SCSS to CSS server-side using [scssphp](https://scssphp.github.io/scssphp/) — no Node.js required.

```

    body { margin: 0; font-family: sans-serif; }

```

Cache is automatically invalidated when the source file changes (`filemtime`).

**Available arguments:** `src`, `identifier`, `priority`, `minify`, `inline`, `deferred`, `media`, `importPaths`, `nonce`, `integrity`, `crossorigin`.

---

Resource Hints
--------------

[](#resource-hints)

Emit `` resource hints into `` to warm up connections and pre-fetch critical resources. All hints are injected via PageRenderer and always land in ``.

```

```

---

Images
------

[](#images)

Process images via TYPO3's native ImageService (supports WebP conversion, cropping, etc). Accept FAL UIDs, File/FileReference objects, or EXT: paths.

### `` — single ``

[](#maiimage--single-img)

```

```

Width/height notation: `800` (exact) · `800c` (centre crop) · `800m` (max, proportional)

**Available arguments:** `image`, `alt`, `width`, `height`, `quality`, `lazyloading`, `lazyloadWithClass`, `fetchPriority`, `decoding`, `crossorigin`, `preload`, `preloadMedia`, `srcset`, `sizes`, `fileExtension`, `class`, `id`, `title`, `additionalAttributes`.

### `` + `` — responsive ``

[](#maipicture--maipicturesource--responsive-picture)

Sources are configured inline in the template — no central YAML file needed.

```

```

Each `` processes the image independently to the specified dimensions. Override the image for a specific breakpoint with the `image` argument.

**`` vs `` attributes:** `class` and `additionalAttributes` apply to the outer `` element. Use `imgClass`, `imgId`, `imgTitle`, `imgAdditionalAttributes`, `imgDecoding`, and `imgCrossorigin` to target the fallback `` independently.

### Automatic WebP/AVIF source sets

[](#automatic-webpavif-source-sets)

The `formats` argument renders one `` per format (most capable first), then the fallback ``. No template duplication needed.

```

```

Output:

```

```

Enable globally via TypoScript so all `` elements get format sources without per-template changes:

```
plugin.tx_maispace_assets.image.alternativeFormats = avif, webp

```

### Image quality

[](#image-quality)

The `quality` argument is available on ``, ``, and ``. It applies to all processed variants (including format alternatives).

```

```

### `` — semantic figure wrapper

[](#maifigure--semantic-figure-wrapper)

```

```

---

Lottie Animations
-----------------

[](#lottie-animations)

Render Lottie JSON animations using the `` web component. The player script is registered once via AssetCollector as a `type="module"` script (non-blocking).

```

```

Configure the player script URL globally via TypoScript (pin a version in production):

```
plugin.tx_maispace_assets.lottie.playerSrc = https://unpkg.com/@lottiefiles/lottie-player@2.0.8/dist/lottie-player.js

```

Or set it per element:

```

```

Pass `playerSrc=""` to skip auto-registration entirely when you include the player via another mechanism.

**Available arguments:** `src`, `autoplay`, `loop`, `controls`, `speed`, `direction`, `mode` (`"normal"` / `"bounce"`), `renderer` (`"svg"` / `"canvas"` / `"html"`), `background`, `width`, `height`, `class`, `playerSrc`, `playerIdentifier`, `additionalAttributes`.

---

Inline SVG
----------

[](#inline-svg)

Embed an SVG file directly as inline markup — required when the SVG needs CSS styling (`fill: currentColor`), JavaScript interaction, or must render without a separate network request.

```

```

The processed markup is cached in the `maispace_assets` cache. The source file must be a trusted filesystem path (EXT: notation or site-relative) — user-supplied SVG is not safe to embed inline without sanitization.

---

SVG Sprites
-----------

[](#svg-sprites)

Icons are registered via `Configuration/SpriteIcons.php` in any extension. The sprite is assembled once, cached, and served from a dedicated HTTP endpoint with long-lived browser cache headers.

```
// EXT:my_sitepackage/Configuration/SpriteIcons.php
return [
    'icon-arrow' => ['src' => 'EXT:my_sitepackage/Resources/Public/Icons/arrow.svg'],
    'icon-close' => ['src' => 'EXT:my_sitepackage/Resources/Public/Icons/close.svg'],
];
```

```

```

The sprite endpoint (`/maispace/sprite.svg` by default) is cached by the browser for one year (`Cache-Control: public, max-age=31536000, immutable`) and supports conditional GET via ETag.

---

Font Preloading
---------------

[](#font-preloading)

Register web fonts in `Configuration/Fonts.php` to automatically emit `` in ``. Fonts are served from their stable public URL — no temp file generation.

```
// EXT:my_sitepackage/Configuration/Fonts.php
return [
    'my-font-regular' => [
        'src' => 'EXT:my_sitepackage/Resources/Public/Fonts/MyFont-Regular.woff2',
        // 'type' is auto-detected from the extension (.woff2 → font/woff2)
    ],
    'my-font-bold' => [
        'src'     => 'EXT:my_sitepackage/Resources/Public/Fonts/MyFont-Bold.woff2',
        'preload' => false, // register without emitting a preload tag
    ],
];
```

Supported auto-detected types: `.woff2` · `.woff` · `.ttf` · `.otf`

---

Multi-site Scoping
------------------

[](#multi-site-scoping)

In a TYPO3 instance with multiple sites, use the `'sites'` key to restrict fonts or SVG symbols to specific sites. Entries without `'sites'` are served on all sites.

```
// SpriteIcons.php or Fonts.php
return [
    'shared-icon' => [
        'src' => 'EXT:shared/Resources/Public/Icons/info.svg',
        // no 'sites' key → available on all sites
    ],
    'icon-brand-a-logo' => [
        'src'   => 'EXT:brand_a/Resources/Public/Icons/logo.svg',
        'sites' => ['brand-a'],
    ],
    'icon-brand-b-logo' => [
        'src'   => 'EXT:brand_b/Resources/Public/Icons/logo.svg',
        'sites' => ['brand-b', 'brand-b-staging'],
    ],
];
```

The site identifier matches the folder name under `config/sites/{identifier}/`. Each site gets its own cached sprite — one build per site, then served indefinitely from cache.

---

TypoScript Configuration
------------------------

[](#typoscript-configuration)

```
plugin.tx_maispace_assets {
    css {
        minify = 1
        deferred = 1
        outputDir = typo3temp/assets/maispace_assets/css/
        identifierPrefix = maispace_
    }
    js {
        minify = 1
        defer = 1
        outputDir = typo3temp/assets/maispace_assets/js/
        identifierPrefix = maispace_
    }
    scss {
        minify = 1
        cacheLifetime = 0
        defaultImportPaths =
    }
    image {
        lazyloading = 1
        lazyloadWithClass =        # e.g. "lazyload" for lazysizes
        forceFormat =              # e.g. "webp" to convert all images globally
        alternativeFormats =       # e.g. "avif, webp" for automatic  sets
    }
    fonts {
        preload = 1                # 0 to suppress all font preload tags globally
    }
    lottie {
        playerSrc =                # URL or EXT: path to lottie-player.js (empty = skip)
    }
    svgSprite {
        routePath = /maispace/sprite.svg
        symbolIdPrefix = icon-
        cache = 1
    }
    compression {
        enable = 1                 # master switch (default: on)
        brotli = 1                 # Brotli — requires PHP brotli extension
        gzip   = 1                 # gzip fallback via gzencode()
    }
}

```

**Debug mode** — all minification and deferral is automatically disabled when a backend user is logged in and `?debug=1` is in the URL (included in `setup.typoscript`, no manual setup needed).

---

Compression
-----------

[](#compression)

Processed CSS and JS files are written to `typo3temp/assets/maispace_assets/` with two compressed siblings alongside the plain file:

```
typo3temp/assets/maispace_assets/css/
├── a3f9d1…css          ← plain (always written)
├── a3f9d1…css.br       ← Brotli, quality 11, BROTLI_TEXT mode
└── a3f9d1…css.gz       ← gzip, level 9

```

The web server serves the appropriate variant based on the client's `Accept-Encoding` header. The SVG sprite is compressed at runtime inside `SvgSpriteMiddleware` (Brotli preferred, gzip fallback).

The `brotli` PHP extension ([PECL](https://pecl.php.net/package/brotli)) is required for `.br` files. When it is absent, `.br` files are silently skipped and gzip-only output is produced — no configuration change is needed.

### Web server configuration

[](#web-server-configuration)

**Nginx** (requires [ngx\_brotli](https://github.com/google/ngx_brotli) for `brotli_static`):

```
location ~* ^/typo3temp/assets/maispace_assets/ {
    brotli_static on;
    gzip_static   on;
    add_header Vary Accept-Encoding always;
    expires max;
    access_log off;
}
```

**Apache** (requires `mod_rewrite` + `mod_headers`):

```

        RewriteEngine On
        RewriteCond %{HTTP:Accept-Encoding} \bbr\b
        RewriteCond %{REQUEST_FILENAME}\.br  -s
        RewriteRule ^(.+)$                   $1.br [L]
        RewriteCond %{HTTP:Accept-Encoding} \bgzip\b
        RewriteCond %{REQUEST_FILENAME}\.gz  -s
        RewriteRule ^(.+)$                   $1.gz [L]

            ForceType text/css
            Header set    Content-Encoding br
            Header append Vary Accept-Encoding

            ForceType application/javascript
            Header set    Content-Encoding br
            Header append Vary Accept-Encoding

            ForceType text/css
            Header set    Content-Encoding gzip
            Header append Vary Accept-Encoding

            ForceType application/javascript
            Header set    Content-Encoding gzip
            Header append Vary Accept-Encoding

```

**Caddy** (built-in, no module required):

```
handle /typo3temp/assets/maispace_assets/* {
    file_server {
        precompressed br gzip
    }
}
```

---

PSR-14 Events
-------------

[](#psr-14-events)

Hook into asset processing by registering listeners in your site package's `Configuration/Services.yaml`:

EventWhen`AfterCssProcessedEvent`After CSS is minified, before caching`AfterJsProcessedEvent`After JS is minified, before caching`AfterScssCompiledEvent`After SCSS is compiled, before caching`BeforeSpriteSymbolRegisteredEvent`Per symbol during auto-discovery — can rename, modify, or veto`AfterSpriteBuiltEvent`After full sprite XML is assembled, before caching`BeforeImageProcessingEvent`Before each image is processed — modify instructions, force WebP/AVIF, or skip`AfterImageProcessedEvent`After each image is processed — inspect result, replace ProcessedFile, log metricsSeven example listeners with full documentation are in `Classes/EventListener/` (inactive by default). Copy the relevant `Services.yaml` block to your site package to activate one.

---

Registering Fonts and Icons from Your Extension
-----------------------------------------------

[](#registering-fonts-and-icons-from-your-extension)

Both registries use the same auto-discovery pattern — no `ext_localconf.php` registration needed:

FilePurpose`EXT:my_ext/Configuration/SpriteIcons.php`Register SVG symbols for the sprite`EXT:my_ext/Configuration/Fonts.php`Register fonts for ``The registries scan all loaded TYPO3 extensions for these files on first use. Later-loaded extensions win on key conflicts, so site packages can override vendor icons/fonts.

---

Critical CSS &amp; JS
---------------------

[](#critical-css--js)

Critical assets (above-the-fold CSS and synchronous JS) are extracted per-page using a headless Chromium instance. This ensures that only the CSS required for the initial viewport is inlined, while the rest of the styles load non-blocking.

### Extraction (CLI)

[](#extraction-cli)

Run the extraction command after every full-page cache flush or major template change:

```
# All sites, all pages, all languages (default)
php vendor/bin/typo3 maispace:assets:critical:extract

# Specific site only
php vendor/bin/typo3 maispace:assets:critical:extract --site=main

# Specific workspace (e.g. 1 = Draft)
php vendor/bin/typo3 maispace:assets:critical:extract --workspace=1

# Specific pages only
php vendor/bin/typo3 maispace:assets:critical:extract --pages=1,12,42
```

The command recursively collects all standard pages from the site root, visits each URL at both mobile and desktop viewports, and caches the result for injection.

### Automatic Injection

[](#automatic-injection)

The `CriticalCssInlineMiddleware` automatically injects the cached critical assets into the `` of HTML responses. Both mobile and desktop CSS are included, scoped via media queries:

```
/* mobile rules */
/* desktop rules */
```

Enable/disable globally via TypoScript:

```
plugin.tx_maispace_assets.criticalCss.enable = 1

```

### CSS Layers support

[](#css-layers-support)

You can wrap the injected critical CSS in a [CSS Layer](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer) to manage specificity and ordering. This is especially useful if your main site styles also use layers.

```
# Wrap critical CSS in @layer {name} { ... }
plugin.tx_maispace_assets.criticalCss.layer = maispace-critical

```

When configured, the injected blocks will look like this:

```

  @layer maispace-critical { /* mobile rules */ }

```

---

Development
-----------

[](#development)

### Running tests

[](#running-tests)

Install dev dependencies, then run the PHPUnit test suite:

```
composer install
composer test
```

Or with the long form (verbose testdox output):

```
vendor/bin/phpunit --configuration phpunit.xml.dist --testdox
```

**Test structure:**

FileWhat it tests`Tests/Unit/Cache/AssetCacheManagerTest.php`Key-building methods, cache delegation`Tests/Unit/Middleware/CriticalCssInlineMiddlewareTest.php`Injection logic, CSS layers, CSP nonces`Tests/Unit/Service/AssetProcessingServiceTest.php``isExternalUrl`, `buildIdentifier`, `buildIntegrityAttrs`, `resolveFlag``Tests/Unit/Service/ImageRenderingServiceTest.php``detectMimeType`, `renderSourceTag`, `renderImgTag`, `addImagePreloadHeader`All tests are pure unit tests — no database, no TYPO3 installation required. PHPUnit mocks are used for all TYPO3 service dependencies.

### CI

[](#ci)

The GitHub Actions workflow (`.github/workflows/ci.yml`) runs on every push and pull request:

JobWhat it checks`composer-validate``composer.json` is valid and well-formed`unit-tests`PHPUnit suite across PHP 8.2 / 8.3 × TYPO3 13.4`static-analysis`PHPStan (`phpstan.neon`, level max)`code-style`EditorConfig (`armin/editorconfig-cli`) + PHP-CS-Fixer (`.php-cs-fixer.php`)`typoscript-lint`TypoScript style/structure (`typoscript-lint.yml`)---

License
-------

[](#license)

GPL-2.0-or-later

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance89

Actively maintained with recent releases

Popularity16

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 67.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~8 days

Total

2

Last Release

62d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b22510e8eb78fdd4b0f42719a309b33260650ea2d27cd98d6968ed61cb67644b?d=identicon)[maispace](/maintainers/maispace)

---

Top Contributors

[![mai-space](https://avatars.githubusercontent.com/u/38419872?v=4)](https://github.com/mai-space "mai-space (35 commits)")[![claude](https://avatars.githubusercontent.com/u/81847?v=4)](https://github.com/claude "claude (15 commits)")[![Copilot](https://avatars.githubusercontent.com/in/1143301?v=4)](https://github.com/Copilot "Copilot (2 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/maispace-assets/health.svg)

```
[![Health](https://phpackages.com/badges/maispace-assets/health.svg)](https://phpackages.com/packages/maispace-assets)
```

###  Alternatives

[contao/core-bundle

Contao Open Source CMS

1231.6M2.3k](/packages/contao-core-bundle)[elgg/elgg

Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.

1.7k15.7k4](/packages/elgg-elgg)[netresearch/rte-ckeditor-image

Image support in CKEditor for the TYPO3 ecosystem - by Netresearch

63991.3k4](/packages/netresearch-rte-ckeditor-image)[b13/assetcollector

Add CSS and SVG files and strings as inline style tag/inline svg to the html code.

10118.4k](/packages/b13-assetcollector)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
