Stub out the global namespace to enable for lazy script loading - javascript

I am using jQuery UI and a few other JS libs which in total make for quite a chunk of JS (even minified and combined). My idea is to not include a script tag in the page but to stub out all functions that I defined as well as the $ sign for jQuery so that my inline JS on the page can still call them but will hit the stub. The stub will then load the .js file and actually call the function. The question now is:
How can I redirect all function calls on the window object/global object to a custom function of mine?
I am not used to dynamic languages so a little advice on how to do this in JS will be appreciated.

As stated previously ... this is likely an exercise in futility. Unless you are a researcher and are being paid to do this (and only this), I'd spend my time just working on my actual product and/or refactoring so that the page requires fewer disparate JS libs (for example. use jquery only, rather than jquery + yui)
edit, though, I suppose in the interest of actually answering the question. You can easily replace any function by simply setting it in javascript. For example ...
$ = function(searchString) {
// if this method is called
// and jquery hasn't been loaded yet
// load jquery (which will overwrite all of your local jquery functions with its own
};
The method to lazy load .js files is well documented throughout the web, for example here:
http://ajaxpatterns.org/On-Demand_Javascript

Well the root of your problem is the usage of library dependent in-line JS. We had an old legacy site that had a bunch of in-line JS in the Smarty templates. I ended up modding Smarty so that I could capture the JS calls and then output them all in the footer. Looked something like this
<!-- mySubContent.inc.html -->
<div id="theTabs">
<ul><li><!--
...
--></li></ul>
<div id="tab1"><!--
...
--></div>
</div>
{capture_js}
$("#theTabs").tabs();
{/capture_js}
<!-- footer.inc.html -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
{render_captured_js}
</script>
</body>
</html>
Anyway, maybe that'll give you some idea about how to tackle your in-line JS problem if you can't refactor the codebase right now. Oh, and read this - http://developer.yahoo.net/blog/archives/2007/07/high_performanc_5.html .

Related

How to include script that includes jQuery without conflicting

I need to load an external application that contains the complete jQuery 3.2.1 library inside of it. Because it is an externally hosted app, it's not realistic to modify the code. However, when I add the script to my page, I end up with lots of errors due to conflicts with other scripts already loaded. As an experiment, I've tried downloading the app and wrapping the contents in an anonymous function, thinking that this would keep the new version of jQuery scoped locally within the app but it didn't make any difference.
Is there a simple way to include this app without modfying it's contents or relying on jQuery.noConflict() which would require many changes to my existing code?
you can use jQuery.noConflict() in your code with limited changes by simply wrapping all of your code that uses jQuery in an IIFE and passing in the instance of jQuery you are using
try something like
<script src="path-to-your-jquery.js"></script>
<script>var $jQ = jQuery.noConflict();</script>
<script>/* your plugins */</script>
<script>
(function($){
/* your code using `$` works fine here*/
})($jQ);
</script>
<script> /* other app code */</script>

jquery set noConflict (or equivalent) BEFORE the jquery script include

Question: Is there a "built-in" or "easy" way to set the jQuery namespace before the jquery.js script include?
Reason I ask is because I'm working on a script that utilizes the jQuery library, and the script is to go on a page that has a library that uses the $ namespace already. Normally I can just use jQuery.noConflict() except the problem is, there is code on the page (which I cannot control) that hooks into mouse movement events and other stuff that basically triggers calls to the 3rd party code over and over the entire time, so often in fact, that more often than not, js errors are happening between the time the jQuery script is loaded and the .noConflict() call is made. I cannot control or change that 3rd party script.
So basically I need the jQuery object to be instantiated without ever taking $ namespace in the first place. Now.. I'm certain that I could reverse engineer jquery.js and make it not do that, but before I go down that road, I figured surely others have come across this situation.. but I could find no official documentation on jQuery for setting this before the script include; only after. But I figured surely others have come across a problem like this anyways, but I can't seem to find any existing questions detailing this (it could be that I just suck at googling).
Can anybody point me in the right direction?
Edit:
To be clear, this is basically the order in which I need things to happen:
<script src='thirdpartyscript.js'></script>
<script type='text/javascript'>
jQuery.noConflict();
</script>
<script src='jquery.js'></script>
I obviously can't call jQuery.noConflict() before the jquery.js script include, since the jQuery object/method doesn't exist yet.
But I can't call it after the script include, because between time it takes for jquery.js to fully execute and the noConflict call to be made, thirdpartyscript is already throwing errors because jquery took control of $, even for just that one single microsecond or w/e.
So.. I know I can edit jquery.js to never use $ namespace, but I was wondering if there was a built-in way or otherwise easy hack to do it before the jquery.js script include, because a) I don't want to hack jquery.js itself, because I'd like to keep pointing to code.jquery.com instead of maintaining my own instance, b) doing so involves actually figuring out what to change (which in fairness I did a quick eyeballing and it doesn't look like much. mostly my caveat is with point "a")
wont work. The object "jQuery" is not available if you include the lib later. You can create an smart "Watcher" for that.
<script src='thirdpartyscript.js'></script>
<script type='text/javascript'>
// Start an interval
var watch = setInterval(function() {
// Check if jQuery available
if(typeof(jQuery) != 'undefined') {
// Stop the interval
clearInterval(watch);
jQuery.noConflict();
}
}, 500);
</script>
<script src='jquery.js'></script>

How to access jQuery after jQuery.noConflict(); - not namespaced

I am in big trouble at the moment. We have a huge JS library that I need to maintain. It uses internally jQuery 1.6.2.
The client where we installed the library uses jQuery 1.3.4 and the fancybox overlay plugin.
After loading these two, he simply throws in a
jQuery.noConflict();
but without saving his jQuery to a variable (namespacing).
Now I need to access his fancybox, but if I use
$.fancybox({...})
or
jQuery.fancybox({...})
I get in both cases an "is not a method error".
I can duplicate the error on my local machine and it would not appear without the jQuery.noConflict(); statement.
We are also doing a noConflict with our jQuery but we save it to another varieable, i.e.
jq162 = jQuery.noConflict();
The problem is the customer is of course unwilling to change anything of his code.
Is there any way how I can access his jQuery / Fancy after this statement and after loading our 1.6.2?
thanks in advance...
UPDATE
the scripts are loaded in the following order:
// client
jquery 1.4.2
jquery fancybox
<script type="text/javascript"> jQuery.noConflict(); </script>
jQuery 1.2.6 which seems to be necessary for Liferay
// now comes my library
jQuery 1.6.2
my scripts
i know, if we could change step 3 to
<script type="text/javascript"> $jq = jQuery.noConflict(); </script> it would work, but right now that is out of my influence.
in 6. myscripts I need to access the fancybox from 2.
any ideas?
It shouldn't be a problem. You must be loading your scripts after the client's scripts (if you're loading yours first, there shouldn't be any problem, your jquery is namespaced, and the clients version will be in jQuery along with the plugin).
So simply namespace his jQuery object before you load your script:
<script>
jq132 = jQuery;
</script>
<script src="yourScripts"></script>
<script>
jq162 = jQuery.noConflict();
console.log(jq132.fancybox);
</script>
UPDATE
As per your update, what you're trying to do is impossible. There is no longer a reachable reference to that jQuery/plugin instance (unless fancybox accidentally leaked a global reference, which I highly doubt). I don't know fancybox, although it's possible that the functionality isn't instance-specific. So it may be possible to just reattach fancybox to your version of jquery, and it will be able to perform all the necessary things. What I said about the reference however, remains true.
Obviously adding a few characters like you suggested (or other similar ways) would solve the problem. But if that is impossible, then your client will have to realise that. It should be proof enough if you simply ask them to access there own plugin under the same conditions - i.e. without changing code.
They should probably have a long and hard think about their entire project. Having to load three different versions of the same product is a sign that something is very very wrong.

JavaScript Autoloader?

Is there a solution out there where I can have JavaScript/jQuery autoload dependent files when needed? For example, consider this scenario:
I have an autoloader script listening for when a particular script needs to be loaded.
A jQuery dialog() plugin is called.
The autoloader is told to listen for when this plugin is called, and loads the jQuery UI.
If more dialogs are called in the future, the required script will not be loaded.
Is this too much effort for simply trying to limit bandwidth? Should I just include all of the core files in one superpackage and be done with it?
Thank you for your time.
Yes you should inclde all of the scripts in one file. Or at least most of them groupped like this: jquery.js, global.js (that's where frequently - on more than one, two pages - used scripts should be) and page_specyfic.js.
Imagine that a dialog() is called and the user has to wait for .js to download and plugins to initialise.
Savings in bandwith (if any) wouldn't be worth harming the users expirience.
There are many examples of on demand script loading out there. For example remy sharp has a code sample on his blog that you could either use as is or turn into a jQuery plugin. Unfortunately it may not work in all browsers.
There is also the jQuery Lazy Plugin Loader which loads jQuery plugins on demand rather than up-front. To use it you would need to set up lazy loading for each piece of jQuery UI you are using as follows (name will be the function name for each piece you use):
$.lazy([{
src: 'jquery-ui-1.8.14.custom.min.js',
name: 'dialog'
}]);
You can also use the techniques in this question about loading jQuery itself on demand. For example you can dynamically create a script tag at the time needed to load jQuery UI.
Finally since you are talking about jQuery UI consider getting it from Google's CDN, which is likely cached in the user's browser anyway.
You can try this new jquery plugin. Works like yeapnope.js but more make sense.
http://plugins.jquery.com/plugin-tags/autoloader
$(document).autoLoader(
{
test: $.ui,
loadScript: "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery- ui.min.js",
complete: function(){
console.log($.ui);
}
}
);
I wouldn't worry too much. The files are cached. Once one page in your site loads the jquery UI (or any other include file like CSS), the next time it's needed it will be in the user's browser cache, never to be loaded again for days/weeks
Sounds like you want a script loader.
You can't generally do synchronous loading of scripts across browsers, though, so script loaders are necessarily asynchronous. What you're asking for isn't exactly possible since the script needs to load, call a callback, and then continue. You wouldn't want to call some plugin and not know whether it is executing synchronously or not, that gets you into a world of problems.
I recommend you look at DeferJS, a script loader for jQuery:
https://github.com/BorisMoore/jsdefer
From your comments, part of your wish seems to be to keep your code organized. I would recommend RequireJs. It lets you break your code up into clearly separated modules with explicit dependencies. Then when you want to go to production, there's a build tool that will merge them all back together into the (request/bandwidth saving) 2-3 files you want to serve.
Yeah, I have also thought about implementing something like this. I am not sure if it would be worthwhile or not in the end but there are quite a few libraries to do this for you like ensure
you could try something like this but it would be a pain. basically you are checking the type of error caught and message if dialog (the function you are trying to call doesn't exist) load the function and try calling the method again. Like I said it would be a pain to do this everywhere unless some elegant solution was thought of.
function loadDialog() {
$('#myDialog').dialog({});
}
try {
loadDialog()
} catch(e) {
if (e && e.type && e.type=='not_defined' && e.message == 'dialog is not defined') {
//load jQuery plugins...
loadDialog();
}
}
This is a follow-up post for a comment above:
<link rel="stylesheet" href="../system/stylesheets/universal.css" />
<link rel="stylesheet" href="../system/stylesheets/jquery-ui.min.css" />
<link rel="stylesheet" href="../system/stylesheets/uploadify.css" />
<link rel="stylesheet" href="system/stylesheets/style.css" />
<script src="../system/javascripts/swfobject.js"></script>
<script src="../system/javascripts/jquery.min.js"></script>
<script src="../system/javascripts/jquery-ui.min.js"></script>
<script src="../system/javascripts/global.jquery.js"></script>
<script src="../system/javascripts/analog.jquery.js"></script>
<script src="../system/javascripts/funtip.jquery.js"></script>
<script src="../system/javascripts/uploadify.jquery.js"></script>
<script src="system/javascripts/install.jquery.js"></script>
<link rel="stylesheet" href="system/templates/stylesheets/style.css" />
<script>
$(document).ready(function() {
$(':text, :password, textarea').funtip();
});
</script>

What is the best way of including a JS file from JS code?

What is the recommended way of including a Javascript file from another Javascript file?
Most people add the JavaScript file to the head of the document:
<script type="text/javascript">
var newfile=document.createElement('script');
newfile.setAttribute("type","text/javascript");
newfile.setAttribute("src", '/myscript.js');
document.getElementsByTagName("head")[0].appendChild(newfile);
</script>
There are libraries that'll do this for you. You can also add a script tag to your document pointing to the file you want to load (from js), which is simplest, but has problems.
http://developer.yahoo.com/yui/yuiloader/
http://www.appelsiini.net/projects/lazyload
Edit: I see a lot of answers that add a script tag to the head of your document. As I said this simple solution has a problem, namely you won't know when the browser has finished loading the script you requested, so you wont know when you can call this code. If you want to use a solution like this you should also add a callback somehow to tell you when the required code was loaded.
jQuery has getScript() function. Also note that Lazy Load mentioned above is only for images. Not for JavaScript files.
$.getScript(url, [callback]);
How about this:
(original link)
<script type="text/javascript">
// Function to allow one JavaScript file to be included by another.
// Copyright (C) 2006-08 www.cryer.co.uk
function IncludeJavaScript(jsFile)
{
document.write('<script type="text/javascript" src="'
+ jsFile + '"></scr' + 'ipt>');
}
</script>
and then to include a second JavaScript file simply add the line:
IncludeJavaScript('secondJS.js');
The page that came from includes some gotchas that arise from this approach, so it's worth looking at before using the method.
Theres also an function built into Scriptaculous that is very easy to use.
Scriptaculous.require("path/to/script.js");
Worth knowing, since Scriptaculous is a very common javascript library these days.
Dojo does it using dojo.require():
dojo.require("your.module.name");
Normally this is a synchronous operation done with XHR. But if you use the xDomain build it will be asynchronous and dojo.addOnLoad() will be raised when the script is loaded.
Read more about it:
Modules
What dojo.require does
Quickstart: custom builds (includes xDomain explanation)
Cross-domain Dojo (specifically dedicated to xDomain stuff).

Categories