As you correctly pointed out the JS lines are generated by Magento. Specifically these are built in app/code/core/Mage/Page/Block/Html/Head.php
which is the block behind the head.phtml
template.
Inside this block we have the method getCssJsHtml
which generates an sprintf
template for each CSS or JS reference.
For the JS scripts the template has the following format: <script type="text/javascript" src="%s"%s></script>
As we can see it accepts 2 variables. First is the URL and the other is a set of parameters; exactly what we need.
To add parameters to a JS link, is very easy. Simply add <params>defer="defer"</params>
in the XML tag which defines the file. For example:
<action method="addJs"><script>mage/cookies.js</script></action>
becomes
<action method="addJs"><script>mage/cookies.js</script><params>defer="defer"</params></action>
Your question though makes a reference to merged JS files. Well, Magento also takes care of that, and merges the files based on their parameters. Meaning if you include some files with the defer parameter, and the others without, Magento will create 2 merge files (one for defer, and one for the others). This is done in the Head.php block file, line 260
foreach ($items as $params => $rows) {
// attempt to merge
$mergedUrl = false;
if ($mergeCallback) {
$mergedUrl = call_user_func($mergeCallback, $rows);
}
// render elements
$params = trim($params);
$params = $params ? ' ' . $params : '';
if ($mergedUrl) {
$html .= sprintf($format, $mergedUrl, $params);
} else {
foreach ($rows as $src) {
$html .= sprintf($format, $src, $params);
}
}
}
As you can see, it groups the files based on their custom parameters (attributes), and merges them.
But be careful when defering JS files. Some of them include functions, plugins, objects that are used inside the templates before the page finishes loading. And as you know defering a JS file means it can load after the HTML has finished loading, so you might end up with Reference error: * is undefined
errors