Asset Management 

The Handlebars extension integrates with TYPO3's modern AssetCollector API to manage JavaScript and CSS assets in your frontend rendering. This feature allows you to register external files and inline code directly through TypoScript configuration.

Overview 

TYPO3 13+ provides the AssetCollector service as the recommended way to register frontend assets. The Handlebars extension fully supports this API through the assets configuration in HANDLEBARSTEMPLATE content objects.

Benefits 

  • Deduplication: Assets with the same identifier are automatically merged across the page
  • Priority Control: Control rendering order with priority options
  • CSP Support: Automatic nonce injection for Content Security Policy compliance
  • Modern API: Uses TYPO3's recommended approach (not deprecated PageRenderer methods)

Asset Types 

The AssetCollector API supports four distinct asset types, all fully supported by this extension:

  1. External JavaScript Files - Link to external .js files
  2. Inline JavaScript Code - Embed JavaScript directly in the page
  3. External CSS Files - Link to external .css files
  4. Inline CSS Code - Embed styles directly in the page

JavaScript Files 

Register external JavaScript files using the javaScript configuration:

10 = HANDLEBARSTEMPLATE
10 {
    templateName = MyTemplate

    assets {
        javaScript {
            my-app-script {
                source = EXT:myext/Resources/Public/JavaScript/app.js
                attributes {
                    async = 1
                    defer = 1
                    crossorigin = anonymous
                }
                options {
                    priority = 1
                    useNonce = 1
                }
            }
        }
    }
}
Copied!

Inline JavaScript 

Add inline JavaScript code using inlineJavaScript:

assets {
    inlineJavaScript {
        my-inline-script {
            source = console.log('Hello from Handlebars'); initMyApp();
            attributes {
                type = module
            }
            options {
                priority = 1
            }
        }
    }
}
Copied!

CSS Files 

Register external stylesheets using the css configuration:

assets {
    css {
        my-styles {
            source = EXT:myext/Resources/Public/Css/styles.css
            attributes {
                media = screen and (max-width: 768px)
            }
            options {
                priority = 1
            }
        }
    }
}
Copied!

Inline CSS 

Add inline styles using inlineCss:

assets {
    inlineCss {
        critical-css {
            source = body { margin: 0; padding: 0; } .container { max-width: 1200px; }
        }
    }
}
Copied!

Configuration Reference 

source (required) 

Type
string
Description

Asset source. For external files, use EXT: syntax or absolute paths. For inline assets, provide the code directly as a string value.

Example
# External JavaScript file
source = EXT:myext/Resources/Public/JavaScript/file.js

# External CSS file
source = EXT:myext/Resources/Public/Css/styles.css

# Inline JavaScript code
source = console.log('Hello');

# Inline CSS code
source = body { margin: 0; }
Copied!

attributes 

Type
array
Description
HTML attributes for the generated tag. Boolean attributes (async, defer, disabled) should be set to 1 to enable them.
JavaScript Attributes
  • async (boolean): Load script asynchronously
  • defer (boolean): Defer script execution
  • nomodule (boolean): Fallback for older browsers
  • type (string): Script type (e.g., "module")
  • crossorigin (string): CORS setting (e.g., "anonymous")
  • integrity (string): Subresource Integrity hash
CSS Attributes
  • media (string): Media query (e.g., "screen", "print")
  • disabled (boolean): Disable stylesheet
  • title (string): Stylesheet title
  • crossorigin (string): CORS setting
  • integrity (string): Subresource Integrity hash
Example
attributes {
    async = 1
    defer = 1
    type = module
    crossorigin = anonymous
    integrity = sha384-abc123def456
}
Copied!

options 

Type
array
Description
AssetCollector-specific options that control asset rendering behavior.
Available Options
  • priority (boolean): Render before other assets (default: 0)
  • useNonce (boolean): Add CSP nonce attribute (default: 0)
Example
options {
    priority = 1
    useNonce = 1
}
Copied!

Complete Examples 

Basic Example 

page.20 = HANDLEBARSTEMPLATE
page.20 {
    templateName = MyPage

    variables {
        title = TEXT
        title.data = page:title
    }

    assets {
        # External JavaScript
        javaScript {
            app-script {
                source = EXT:myext/Resources/Public/JavaScript/app.js
                attributes {
                    defer = 1
                }
            }
        }

        # External CSS
        css {
            main-styles {
                source = EXT:myext/Resources/Public/Css/main.css
            }
        }
    }
}
Copied!

Advanced Example with Priority 

page.20 = HANDLEBARSTEMPLATE
page.20 {
    templateName = MyPage

    assets {
        # High-priority critical CSS
        css {
            critical-styles {
                source = EXT:myext/Resources/Public/Css/critical.css
                options {
                    priority = 1
                }
            }
        }

        # Regular stylesheet with media query
        css {
            responsive-styles {
                source = EXT:myext/Resources/Public/Css/responsive.css
                attributes {
                    media = screen and (min-width: 768px)
                }
            }
        }

        # Inline critical CSS (highest priority)
        inlineCss {
            above-the-fold {
                source = body { font-family: sans-serif; } h1 { font-size: 2em; }
                options {
                    priority = 1
                }
            }
        }

        # Modern JavaScript module
        javaScript {
            app-module {
                source = EXT:myext/Resources/Public/JavaScript/app.js
                attributes {
                    type = module
                }
                options {
                    useNonce = 1
                }
            }
        }

        # Legacy fallback for older browsers
        javaScript {
            app-legacy {
                source = EXT:myext/Resources/Public/JavaScript/app.legacy.js
                attributes {
                    nomodule = 1
                    defer = 1
                }
            }
        }

        # Inline initialization code
        inlineJavaScript {
            app-init {
                source = window.APP_CONFIG = { apiUrl: '/api' };
                options {
                    priority = 1
                }
            }
        }
    }
}
Copied!

CDN Example with Security 

assets {
    javaScript {
        cdn-library {
            source = https://cdn.example.com/library.js
            attributes {
                crossorigin = anonymous
                integrity = sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC
                defer = 1
            }
        }
    }

    css {
        cdn-styles {
            source = https://cdn.example.com/styles.css
            attributes {
                crossorigin = anonymous
                integrity = sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN
            }
        }
    }
}
Copied!

Migration from Legacy Methods 

If you're using the legacy headerAssets or footerAssets configuration, consider migrating to the modern assets approach:

Before (Legacy) 

10 = HANDLEBARSTEMPLATE
10 {
    templateName = MyTemplate

    headerAssets = TEXT
    headerAssets.value = <script src="path/to/script.js"></script>

    footerAssets = TEXT
    footerAssets.value = <script>console.log('footer');</script>
}
Copied!

After (Modern) 

10 = HANDLEBARSTEMPLATE
10 {
    templateName = MyTemplate

    assets {
        javaScript {
            my-script {
                source = EXT:myext/Resources/Public/JavaScript/script.js
            }
        }

        inlineJavaScript {
            footer-script {
                source = console.log('footer');
            }
        }
    }
}
Copied!

Benefits of Migration 

  • Automatic asset deduplication across multiple content elements
  • Better control over rendering order via priority
  • Content Security Policy nonce support
  • Type-safe attribute handling
  • Future-proof implementation using TYPO3's recommended API

Best Practices 

Unique Identifiers 

Always use unique, namespaced identifiers across your entire page to avoid conflicts:

# Good: Namespaced identifier
my-extension-app-script {
    source = ...
}

# Bad: Generic identifier (may conflict with other extensions)
app {
    source = ...
}
Copied!

Priority Management 

Use priority = 1 for assets that must load early:

# Critical inline CSS should have priority
inlineCss {
    critical {
        source = ...
        options.priority = 1
    }
}

# Regular stylesheets can have normal priority
css {
    theme {
        source = ...
        # No priority option = loaded after priority assets
    }
}
Copied!

Content Security Policy 

Enable useNonce = 1 for inline scripts when using CSP:

inlineJavaScript {
    inline-config {
        source = window.config = { /* ... */ };
        options.useNonce = 1
    }
}
Copied!

Module vs Classic Scripts 

Use type = module for ES6 modules and provide nomodule fallback for older browsers:

# Modern browsers
javaScript {
    app-module {
        source = EXT:myext/Resources/Public/JavaScript/app.module.js
        attributes.type = module
    }
}

# Legacy browsers
javaScript {
    app-legacy {
        source = EXT:myext/Resources/Public/JavaScript/app.legacy.js
        attributes.nomodule = 1
    }
}
Copied!

Troubleshooting 

Assets Not Appearing 

If assets don't appear in the rendered page:

  1. Check identifiers are unique - Duplicate identifiers will cause the last one to win
  2. Verify source is not empty - Empty sources will throw an exception
  3. Check for exceptions - Configuration errors will halt rendering and display an error
  4. Ensure AssetCollector is initialized - Only works in frontend context

Duplicate Assets 

If assets appear multiple times, check for:

  • Duplicate identifiers in different content objects
  • Multiple HANDLEBARSTEMPLATE objects registering the same asset

Use unique, namespaced identifiers to prevent conflicts:

# Use extension prefix to avoid conflicts
my-ext-my-script {
    source = ...
}
Copied!

Configuration Errors 

The extension throws InvalidAssetConfigurationException for:

  • Unknown asset type (valid types: javaScript, inlineJavaScript, css, inlineCss)
  • Invalid asset type configuration (must be an array)
  • Invalid or empty identifier
  • Invalid asset configuration (must be an array)
  • Missing source parameter
  • Empty source value (after trimming whitespace)

These errors will halt page rendering and display an exception message. Check your TypoScript configuration to resolve the issue.

Boolean Attributes Not Working 

Boolean attributes require the value 1 (or any truthy value) to be enabled:

# Correct
attributes {
    async = 1        # Will output: async="async"
    defer = 1        # Will output: defer="defer"
}

# Incorrect - will not be output
attributes {
    async = 0        # Omitted from output
    defer =          # Omitted from output
}
Copied!

See Also