In Joomla, you can add scripts using JHtml::script
or $doc->addScript
, and if you add the same path twice, it will only get included once in the output <head>
:
JHtml::script("path/to/jquery.scrollTo.min.js");
This will not deduplicate the same script at different paths. Unfortunately, there is no built-in way to do this that I can see. For JQuery itself, you can use the shipped PHP library:
JHTML::_('jquery.framework');
Hacky way server-side:
You can use this hacky way. It simply checks all the scripts that have been added already, and only adds the new path if none of the existing scripts match a regex:
if (! isScriptAdded('/^jquery\.scrollTo\b.*\.js$/')) {
JHtml::script("path/tojquery.scrollTo.min.js");
}
function isScriptAdded($scriptRegex) {
$document = JFactory::getDocument();
$headData = $document->getHeadData(); # JHtml::script and $document->addScript add to this
foreach ($headData['scripts'] as $script) {
if (preg_match($scriptRegex, basename($script))) {
return true;
}
}
return false;
}
Hacky way client-side:
You could load the library in Javascript, setting a global variable before you do so. For example, this is Facebook's Javascript SDK v2.3 code snippet:
window.fbAsyncInit = function() {
FB.init({
appId : 'your-app-id',
xfbml : true,
version : 'v2.3'
});
};
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
The first part sets a global variable, window.fbAsyncInit
, and the second part actually loads the external script by dynamically appending a new <script>
tag. If you wanted to make it idempotent, you could just surround it with this if
statement:
if (! window.fbAsyncInit) {
// Facebook snippet here
// ...
}
This is hacky, because you're hoping that everybody else is loading this library in the same way and setting the global variable correctly (that is, before loading and executing the library). In this case, you're hoping especially that the appId
and version
params don't change. Also, it would theoretically be better if the server could send just one snippet, instead of multiple snippets that know how to detect each other.
What about using a CDN?
Some popular Javascript libraries are on well known CDNs. For example, Google offers a CDN to host Web Font Loader and other libraries. The hope is that the user agent will have the library in its cache even before it visits your website for the first time. If two extensions both use the same CDN, then the library does not need to be downloaded twice. The main downside of using a CDN is that your website now depends on a third party, which is why I would recommend not taking this approach by default with extensions that are going to be shared online.