Overview
System - Bundler automatically combines multiple JavaScript and CSS files into optimized bundles, dramatically improving your site's performance.
Problem: Modern Joomla sites typically load 40+ separate JavaScript and CSS files on every page. Each file is a separate HTTP request, slowing down page load times.
Solution: Bundler combines these files into just 2-4 optimized bundles, minifies them, and compresses them with gzip.
Real Results:
- 90% fewer HTTP requests (40 files → 4 bundles)
- 70-80% smaller file sizes (with gzip compression)
- Automatic updates when extensions are installed or updated
- Zero ongoing maintenance after initial setup
Installation
- Download the plugin package
- Go to System → Extensions → Install
- Upload and install the package
- Go to System → Plugins
- Find System - Bundler and enable it
- Click the plugin name to configure it
Quick Start Guide
That's an oxymoron for this plugin - there isn't a quick way to use it. You either plan, test, and iterate - or you don't use it at all. It's that simple, which is to say - it isn't simple at all. This plugin allows you to achieve an objective in a way that no other plugin can offer. Once configured, it will deliver the same results time-and-time again. Making changes is relatively simple, but your success depends on your willingness to go through the necessary steps to achieve success.
Developer Note:
You'll have great success bundling CSS, so start there. That's where you'll find your biggest gains. Common CSS on RicheyWeb.com went from 12 scripts to 2. Defer-only scripts are bundled together - reducing 5 scripts to 1, and defer+async scripts were bundled together - reducing 3 scripts to 1. Steps to success can be found below. Attention to detail pays off with this plugin.
Step 1: Identify Site-Wide Assets
CRITICAL: Only bundle assets that load on EVERY page of your site.
Good candidates:
- Template core files
- Bootstrap framework files
- System-level plugins
- Site-wide navigation/footer assets
Bad candidates:
- Component-specific scripts
- Conditionally-loaded modules
- Page-specific features
Step 2: Create Your First Bundle
- In plugin settings, click Add Bundle
- Set Bundle Name:
scripts-main - Set Type: JavaScript
- Set Attributes: (leave empty for now)
- Add files (see next section)
- Save the plugin
Step 3: Test
- Visit your homepage
- Open browser DevTools (F12)
- Go to Network tab
- Refresh page
- Look for
plg_system_bundler/scripts-main_[version].js - Verify original files are no longer loading
Understanding Asset Specification
This is the most important section. Read it carefully.
System - Bundler gives you TWO ways to specify which assets to bundle. Understanding the difference is critical.
Method 1: By File Path (Automatic Detection)
How it works:
- You specify the file's URI/path
- Plugin scans WebAssetManager on its first page load
- If an asset with that URI is found, it's removed and bundled
- If not found on this page, nothing happens
When to use:
- The asset loads on every page (or most pages)
- You can easily identify the file path
- You want the plugin to automatically detect the asset
Example:
File: media/system/js/core.js
Asset: (leave blank)
How to find file paths:
- Open browser DevTools → Network tab
- Reload your page
- Look for .js or .css files
- Copy the path (e.g.,
media/system/js/core.js)
Method 2: By Asset Name (Explicit Control)
How it works:
- You specify the asset's registration name
- Plugin ALWAYS removes this asset, whether it exists or not
- Plugin registers a blank asset with the same name to override it
- Works even if the asset doesn't load during your test
When to use:
- The asset loads conditionally (only on certain page types)
- You want guaranteed removal regardless of page context
- You're a power user who knows the asset registration names
Example:
File: media/system/js/core.js
Asset: core
How to find asset names:
- Check extension source code
- Use browser DevTools to inspect script tag attributes with debug enabled
- Look in extension's joomla.asset.json file
- Ask the extension developer
Combining Both Methods
You can (and often should) specify both:
File: media/system/js/core.js
Asset: core
This provides:
- The file path for bundling (what to include)
- The asset name for guaranteed removal (what to disable)
If you specify ONLY the asset name without a file path, the plugin will try to remove it but won't know what to bundle. This will cause errors. Always specify the file path.
Configuration Walkthrough
Bundle Settings
Bundle Name
Required
A unique identifier for this bundle.
Examples:
scripts-mainscripts-deferstyles-globalbootstrap-components
Rules:
- Use lowercase
- No spaces (use hyphens)
- Must be unique across all your bundles
Type
Required
Choose JavaScript or CSS.
Important: JavaScript and CSS must be in separate bundles. You cannot mix them.
Attributes (JavaScript only)
Optional
Controls how the bundled script executes.
Options:
- None - Normal blocking script (executes immediately)
- defer - Executes after HTML parsing completes
- async - Executes as soon as it's downloaded
- Both - Browser chooses best strategy
CRITICAL RULE: Scripts with different attributes MUST be in separate bundles.
Why? If you bundle a deferred script with a normal script, both will use the bundle's attributes, potentially breaking execution order.
Example - WRONG:
Bundle: scripts-main
Attributes: (none)
Files:
- media/system/js/core.js (normally loaded with defer)
- media/vendor/bootstrap/js/bootstrap.js (normally loaded without defer)
This will force core.js to execute immediately instead of being deferred, potentially breaking things.
Example - CORRECT:
Bundle: scripts-normal
Attributes: (none)
Files:
- media/vendor/bootstrap/js/bootstrap.js
Bundle: scripts-defer
Attributes: defer
Files:
- media/system/js/core.js
File Settings
File (Required)
The file path/URI of the asset to bundle.
Format:
- Can start with or without leading slash
- Relative to site root
- Do NOT include domain or protocol
Valid:
media/system/js/core.js
/media/system/js/core.js
templates/cassiopeia/js/template.js
Invalid:
https://yoursite.com/media/system/js/core.js
../media/system/js/core.js
Asset (Optional)
The WebAssetManager registration name for this asset.
When to use:
- You know the exact asset name
- The asset loads conditionally
- You want guaranteed removal
How to find it: Most assets follow patterns:
- Core:
core.{name}(e.g.,core.core-js) - Components:
com_{component}.{name} - Plugins:
plg_{group}_{element}.{name} - Templates:
template.{template}.{name}
Check the extension's joomla.asset.json file or source code for exact names.
Finding Asset Information
Finding File Paths (Easy - Debug Required)
Method 1: Browser DevTools
- Open your site in browser
- Press F12 to open DevTools
- Go to Network tab
- Check Disable cache
- Reload the page
- Look for .js and .css files in the list
- Copy the path from the Name column
Example:
Name: media/system/js/core.js
Status: 200
Type: script
Use media/system/js/core.js as your file path.
Method 2: View Page Source
- Right-click page → View Page Source (Ctrl+U / Cmd+U)
- Search for
<scriptor<link rel="stylesheet" - Find the src/href attributes
- Copy everything after your domain
Example HTML (without debug):
<script src="/media/system/js/core.js" defer></script>
Use media/system/js/core.js as your file path.
Note the defer attribute - you'll need this for bundle configuration.
Finding Asset Names (Advanced)
Asset names are how Joomla's WebAssetManager internally identifies registered scripts and styles. You have two approaches:
Easy Way: Enable debug mode temporarily (5 minutes of work)
Long Way: Dig through PHP code and JSON files (30+ minutes of work)
Most users should use debug mode. The long way is only necessary if you can't enable debug on a production site.
Method 1: Enable Joomla Debug Mode (Easy - Recommended)
Enable debug:
System → Global Configuration → System → Debug System: Yes
Then view page source:
With debug enabled, Joomla adds data-asset-name attributes to script and link tags:
Example HTML (with debug enabled):
<script src="/media/system/js/core.js" defer data-asset-name="core"></script>
The data-asset-name value is what you need: core
Steps:
- System → Global Configuration → System → Debug System: Yes
- Save and close
- Load your site's frontend
- Right-click → View Page Source (Ctrl+U / Cmd+U)
- Search for the script/style file path you want to bundle
- Look for
data-asset-name="..."in that tag - Copy the asset name value
- Go back and turn debug mode off (for security/performance)
Why this is easy: 5 minutes, no file editing, no code reading, just copy/paste.
Method 2: Check joomla.asset.json Files (Long Way)
If you can't enable debug mode (production site, no access to config, etc.), you can find asset names by reading the extension's asset definition files.
Common locations:
/media/system/joomla.asset.json (Joomla core)
/media/com_{component}/joomla.asset.json (Components)
/media/plg_{group}_{plugin}/joomla.asset.json (Plugins)
/media/templates/site/{template}/joomla.asset.json (Templates)
/media/mod_{module}/joomla.asset.json (Modules)
Example from template's joomla.asset.json:
{
"$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
"name": "template.cassiopeia",
"version": "4.0.0",
"assets": [
{
"name": "template.cassiopeia.user",
"type": "script",
"uri": "templates/cassiopeia/js/user.js",
"attributes": {
"defer": true
}
}
]
}
From this you learn:
- Asset name:
template.cassiopeia.user - File path:
templates/cassiopeia/js/user.js - Attributes: defer
Steps:
- Identify which extension loads the asset (from file path in Network tab)
- Navigate to that extension's media folder on your server (FTP/file manager)
- Look for
joomla.asset.json - Open the file and find the asset definition with matching
uri - Copy the
namevalue
Why this is long: Have to identify the extension, navigate file system, open JSON files, search through them. Repeat for every asset.
Method 3: Search Extension PHP Code (Long Way - Last Resort)
Some extensions register assets in PHP code instead of JSON files.
Look for these method calls:
$wa->registerScript('asset-name', 'path/to/file.js');
$wa->registerAndUseScript('asset-name', 'path/to/file.js');
$wa->registerStyle('asset-name', 'path/to/file.css');
$wa->registerAndUseStyle('asset-name', 'path/to/file.css');
The first argument is the asset name.
Common file locations:
/plugins/{group}/{plugin}/src/Extension/{Plugin}.php
/components/com_{component}/src/View/{View}/{Format}.php
/templates/{template}/index.php
/templates/{template}/html/{component}/{view}/default.php
/modules/mod_{module}/mod_{module}.php
Example from a plugin:
$wa = $doc->getWebAssetManager();
$wa->registerAndUseScript(
'plg_system_myplugin.main', // ← This is the asset name
'media/plg_system_myplugin/js/main.js',
[],
['defer' => true]
);
Asset name: plg_system_myplugin.main
Steps:
- Identify which extension loads the asset (from file path)
- Download or access extension files (FTP/file manager)
- Search ALL PHP files for
registerScript,registerAndUseScript,registerStyle, orregisterAndUseStyle - Find the call where the second argument matches your file path
- Copy the first argument (the asset name)
Why this is last resort: Have to download files, search through code, understand PHP. Very time-consuming.
Realistic Expectations:
You'll probably encounter a mix of both. Some will be in json, some in PHP. In some templates, the assets are registered via a variable - so you'll need to search for registerAndUseScript/registerAndUseStylesheet and interpret the code to figure out what the asset name is. There is not really any method to do this automatically - but it only needs to be done once per asset.
Quick Reference: Which Method When
For File Paths (Always Easy):
- DevTools Network tab → See all loaded files, copy paths ✅
- View Page Source → See attributes (defer/async), verify paths ✅
For Asset Names (Choose Your Path):
- Debug Mode → EASY: 5 minutes, just enable and copy from page source ✅✅✅
- joomla.asset.json → LONG: 30+ min, navigate files, search JSON ⏱️
- PHP Code Search → LONGEST: Download files, grep code, understand PHP ⏱️⏱️
Recommendation: Just enable debug mode for 5 minutes. Seriously. It's so much easier than the alternatives.
WARNING: Do NOT guess asset names based on patterns. Wrong names mean the asset won't be removed, bundles won't work correctly, and you'll waste time troubleshooting. Always verify using one of the methods above.
Best Practices
Start Small
Begin with 2-3 obviously site-wide files. Test thoroughly. Add more gradually.
Group by Attributes
Create separate bundles for normal, deferred, and async scripts:
scripts-normal(no attributes)scripts-defer(defer only)scripts-async(async only)
Test Across Page Types
After configuration, visit:
- Homepage
- Article pages
- Category pages
- Contact forms
- Any page type your site uses
Ensure everything still works. If something breaks, that asset probably wasn't site-wide.
Use Asset Names for Certainty
If you know the asset name, specify it. This ensures removal even if the asset doesn't load during your test page.
Document Your Configuration
Keep notes about what you bundled and why. Future you (or another admin) will thank you.
Monitor After Updates
When you update extensions, check if they:
- Changed file paths
- Added new assets
- Removed old assets
Bundles rebuild automatically, but you may need to update your configuration. The media_version cache item will need to be cleared after each update if you've enabled any kind of client-side cache. System > Cache > find media_version, clear it.
Troubleshooting
Bundle File is Empty or Tiny
Problem: Generated bundle is 0KB or very small
Causes:
- File paths are incorrect
- Files don't exist at specified paths
- Permissions prevent reading files
Solution:
- Verify file paths in DevTools Network tab
- Check files exist on server
- Enable Joomla debug mode and check error logs
- Look for "System - Bundler could not add file" messages
Assets Still Loading Individually
Problem: Original files still appear in page source
Causes:
- Asset name specified but doesn't match actual name
- Asset added via deprecated methods (
$doc->addScript()) - Template renders scripts directly in PHP
- Asset loads after plugin runs
Solution:
- Verify asset name is correct
- Check if extension uses WebAssetManager
- Try specifying both file path AND asset name
- Check if template uses deprecated methods
JavaScript Errors After Bundling
Problem: Console shows errors after enabling bundles
Causes:
- Scripts bundled with wrong attributes
- Execution order changed
- Dependencies broken
- Mixed site-wide and page-specific scripts
Solution:
- Check bundle attributes match original scripts
- Ensure defer/async scripts are in separate bundles
- Verify all bundled scripts are truly site-wide
- Temporarily disable bundle to confirm it's the cause
Bundles Not Updating After Changes
Problem: Made config changes but bundles still show old content
Causes:
- Browser cache
- Joomla cache
- CDN/reverse proxy cache
Solution:
- Clear Joomla cache (System → Clear Cache)
- Hard refresh browser (Ctrl+Shift+R / Cmd+Shift+R)
- Clear CDN cache if using one
- Check file timestamp on server
Template Assets Not Bundled
Problem: Template's JavaScript/CSS still loading separately
Causes:
- Template uses deprecated
$doc->addScript()methods - Template renders scripts directly in HTML
- Asset name not specified
Solution:
- Specify the asset name explicitly
- Check template code for deprecated methods
- Contact template developer about WebAssetManager support
Advanced Usage
Multiple Bundles Strategy
Create bundles based on asset characteristics:
By Load Timing:
Bundle: scripts-blocking
Attributes: (none)
Files: Critical scripts that must load first
Bundle: scripts-defer
Attributes: defer
Files: Enhancement scripts that can wait
Bundle: scripts-async
Attributes: async
Files: Independent scripts (analytics, etc.)
By Framework:
Bundle: bootstrap-components
Type: JavaScript
Files: All Bootstrap JS components
Bundle: bootstrap-styles
Type: CSS
Files: Bootstrap CSS files
Conditional Asset Strategy
For assets that load on MOST but not ALL pages:
- Use asset name for guaranteed removal
- Accept that it bundles into all pages
- Weigh the tradeoff: Extra KB on pages that don't need it vs. complexity of multiple bundles
Example: If an asset loads on 90% of pages, bundling it everywhere is probably fine. The cache benefit outweighs the small overhead on the 10% of pages.
Debugging Mode
Enable Joomla debug mode to see detailed error logs:
configuration.php:
public $debug = 1;
public $error_reporting = 'maximum';
Check administrator/logs/ for Bundler messages.
Manual Bundle Regeneration
To force bundles to regenerate:
- Go to plugin settings
- Make any change (even trivial)
- Save
This clears cache and triggers full rebuild.
Limitations
What Can Be Bundled
Supported:
- Assets registered via WebAssetManager
- Template files using WebAssetManager
- Plugin/module/component assets using WebAssetManager
- Any properly registered JavaScript or CSS
Not Supported:
- ES6 modules (type="module")
- Assets using deprecated
$doc->addScript()/$doc->addStyleSheet() - Inline scripts or styles
- Directly rendered HTML in templates
- External/CDN-hosted files
Note: CDN-hosted files doesn't mean that you can't use a CDN for YOUR files. If you're using someone else's CDN hosted files, this won't help you.
Deprecated API Note
$doc->addScript() and $doc->addStyleSheet() are deprecated in Joomla 4+ and will be removed in Joomla 7.
If an extension still uses these methods:
- It won't work with Bundler
- It will break in Joomla 7
- Contact the developer about updating to WebAssetManager
Bundler only supports modern, future-proof APIs.
Site-Wide Assets Only
You must only bundle assets that load on EVERY page.
Bundling page-specific assets causes:
- Unnecessary code on pages that don't need it
- Larger initial download
- Wasted bandwidth
- Potential functionality issues
When in doubt, don't bundle it.