Looking into RequireJS but unlike Head.JS which downloads in undetermined order but evaluates in a determine order, RequireJS seems different
Normally RequireJS loads and evaluates scripts in an undetermined order.
Then it shows how to prefix order! to the script names for explicit ordering etc..
Then in the examples:
require(["jquery", "jquery.alpha", "jquery.beta"], function($) {
//the jquery.alpha.js and jquery.beta.js plugins have been loaded.
$(function() {
$('body').alpha().beta();
});
});
So if jquery.alpha is downloaded and evaluated before jquery then surely this would cause a problem? Forgetting any client code usage such as function body above, if like most plugin they attach to jQuery.fn then at stage of evaluation then jQuery will undefined in this scenario.
What am I missing here?
RequireJS is not designed to load plain javascript, but to load defined modules. The module format looks something like:
define(['a', 'b'], function(a, b) {
return { zzz: 123 };
});
The important thing to note is that all of the module code is inside an anonymous function. So if the file is run in an arbitrary order, it doesn't matter, because all it does is register the module. The module code is then run in dependency order, with the return value becoming the module object, which is passed as a parameter to code that uses the module.
If you are trying to load plain files, this will not work correctly for you. There is the order plugin to force load order in that case.
It should be noted that that example uses the custom made version of "requirejs and jquery" packaged together, which I believe means that jquery will always be available first.
If you have problems, you can always wrap your plugins within a module definition and make sure they depend on jquery themselves, again ensuring the order is correct:
/* SPECIAL WRAPPING CODE START */
define(['jquery'], function(jQuery) {
// .... plugin code ....
/* SPECIAL WRAPPING CODE END */
});
You are correct, without something to aid in the order an exception will occur. The good news is RequireJS has an Order plug-in to help in this.
I'm currently evaluating RequireJS...
And Here Is An Example of One of My Files:
The 'order!' command will load files for you sequentially. You can (then) use the callback to load other (support) files.
<script src="Loaders/RequireJS/requireJS.js" type="text/javascript"></script>
<script src="Loaders/RequireJS/order.js" type="text/javascript"></script>
<script type="text/javascript">
require(["Loaders/RequireJS/order!././Includes/JavaScript/jQuery/Core/jquery-1.3.2.js",
"Loaders/RequireJS/order!././Includes/JavaScript/jQuery/Core/jquery.tools.min.js",
"Loaders/RequireJS/order!././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tmpl.js"], function() {
require(["././Includes/JavaScript/jQuery/jGeneral.js",
"././Includes/JavaScript/jQuery/autocomplete.js",
"././Includes/JavaScript/jQuery/jquery.ErrorWindow.js",
"././Includes/JavaScript/jQuery/jquery.ValidationBubble.js",
"././Includes/JavaScript/jQuery/jquery.Tootltip.js",
"././Includes/JavaScript/jQuery/jquery.Extensions.js",
"././Includes/JavaScript/jQuery/jquery.Toaster.js"], null);
require(["././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.dimensions.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jQuery.Color.Animations.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.corners.min.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tipsy.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.numberformatter-1.1.0.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tipsy.js"], null);
});
</script>
In All Honesty:
I'm looking at various asynchronous resource-loaders and I'm having a hard-time finding one that does everything I need. I'm also finding the documentation in each one lacking.
Related
Sorry, I put this again since the old post got merged into some post that doesn't relate to my question ... I'm new to React and trying to convert a php website into react components. However, in old website there are some function in pure jquery and from CDSNJS. The external javascripts function are not binding well with my component and I cannot figure out how to. Please can anyone give me some advice.
Case 1:
I got a an external function like this:
;(function ($) {
/* Global variables */
var prty, flickr;
$.fn.flickrGallery = function(flickrID) {
//Defaults settings
var opts = $.extend({}, {
Key:prty.settings["Key"],
Secret:prty.settings["Secret"],
User:prty.settings["User"],
PhotoSet:flickrID,
Speed:400,
navigation:1,
keyboard:1,numberEl:1 });
//Setup
prty.Setup($(this), opts);
}; //End FN
prty = {
.... Internal code
};
})(jQuery);
And this is my component's code:
async componentDidMount() {
//$('#gallery').flickrGallery(2); // Not work
//const el = ReactDOM.findDOMNode(this.display); Not work
//$(el).vectorMap({map: 'world_mill_en'});
//$(el).flickrGallery(2);
//const el = ReactDOM.findDOMNode(this.domRef); Not work
//window.$('#addSupModal').modal('show')
//$(el).flickrGallery(2);
window.$(this.productIntro).flickrGallery(2); Not work
}
Every time I run, an error like this appears:
Unhandled Rejection (TypeError): window.$(...).flickrGallery is not a function
Case 2:
Beside the case above, I'm also using a lib from CDNJS
<!-- jQuery 1.8 or later, 33 KB -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Fotorama from CDNJS, 19 KB -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/fotorama/4.6.4/fotorama.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fotorama/4.6.4/fotorama.js"></script>
I have tried including these links into index.html but the same error as above happens when I run ... Please help
Try to access the flickrGallery function via window.jQuery instead of window.$.
The plugin add the flickrGallery function to jQuery. In most of the time, jQuery should be the same as $. However, in some cases, multiple version of jQuery are loaded and jQuery may no longer be equals to $.
The following suggestions were told to be not solving the problem. I will keep them below in case someone find it useful.
It looks like your react component script is executed and rendered before the external scripts is being executed. There are many causes to it and one of the reasons is the ordering of your script tags.
In the document head, make sure the ordering of your script tag is as follow.
<script src="path/to/external/library.js"></script>
<script src="path/to/your/react/script.js"></script>
These script tags do not have the defer nor async attribute, suggesting they should be downloaded, parsed and executed in order. The external script is executed first.
In other cases, where there are defer, async, etc. attributes are in the script tag, you can understand the order of execution by reading this cheat sheet.
If you are using plugin which adds its functionality to some global variable, your bundler may tree-shake it away because it does not detect any usage of its exports and thinks the module is not needed. In this case, you have to add side effect import (Doc).
In your entry module, add this at the very top:
import 'some-jquery-plugin'
I was following the jsfiddle link http://jsfiddle.net/phusick/894af and when I put the same code into my application, I was getting "reference error: declare is not defined". I have following declarations on top of my js file:
dojo.require("dojo._base.declare");
dojo.require("dojox.form.CheckedMultiSelect");
Thanks in advance for your help.
With Dojo AMD you can tell which module maps to which parameter, for example dojo/_base/declare which is mapped to a variable called declare.
However, in non-AMD code you don't have this possibility. In stead of that you have to do the following:
dojo.require('dojo._base.declare'); // Import
dojo.declare(/** Parameters */); // Use
And actually, modules in dojo/_base are already inside the Dojo core if I'm not mistaken, so you could leave away the dojo.require() line in this case.
For the following AMD code:
require(["dojo/_base/declare"], function(declare) {
var MyCheckedMultiSelect = declare(CheckedMultiSelect, {
/** Stuff */
});
});
You can write the following in non-AMD:
var MyCheckedMultiSelect = dojo.declare(CheckedMultiSelect, {
/** Stuff */
});
However, make sure that when you're running Dojo 1.7, that you disable async mode, for example:
<script>
dojoConfig = {
parseOnLoad: false,
async: true
};
</script>
This rule applies to most, if not all, modules in dojo/_base and several DOM modules, for example:
dojo/_base/xhr: Methods like put(), get(), ... become dojo.xhrGet(), dojo.xhrPut(), ...
dojo/_base/lang: Methods like mixin(), hitch(), ... become dojo.mixin(), dojo.hitch(), ...
dojo/dom: Methods like byId() become dojo.byId()
dojo/on: You have to use dojo.connect() for this
dijit/registry: Methods like byId() become dijit.byId()
...
However, if you're using Dojo 1.7, then you should probably just leave the code in AMD even if all other code is written in non-AMD code. Eventually you will have to upgrade all your code to AMD-syntax, if you're now investing time to convert the code to non-AMD and you later have to convert it to AMD again, you're doing the same work twice.
I often start my JavaScript apps like this:
jQuery(function($) {
... code for the app ...
});
I'm just starting to use RequireJS, and will start the app like this:
define(['jquery'], function($) {
... code for the app ...
});
Now, as I don't want the app to start processing until all the HTML has been loaded, I've combined the two like this:
require(['jquery'], function($) {
$(function($) {
... code for the app ...
});
});
Is that the way to do it?
The RequireJS documentation touches on this and offers has a slightly more convenient option:
require(['domReady!'], function (doc) {
//This function is called once the DOM is ready,
//notice the value for 'domReady!' is the current
//document.
});
Note that you will need to download the domReady plugin, and if you have a very complex page you may wish to use the "explicit function call" method that they also show... Although then it looks an awful lot like what you're already doing with jQuery.
So the main diferences between define and require in this scenario is, one declare a module and the second one call this defined module, then if it is not loaded, the browser download the js library.
To take control about when your require files will download, you need to use the domReady plugin.
You need to put the js library at you require.config, I usually put at the same directory as declared at the baseUrl property, for example:
require.config({
baseUrl: "js/lib",
paths:{
filter:"../src/filter",
addPanel: "../src/edit-panel"
}
}
I put the domReady.js at the js/lib/ folder.
So, then you can use the require method at any place of you html file:
require(['jquery!'], function ($) {
});
Note that I use the symbol ! to indicate that this library is load after the completely page load.
As the box at the top of the page, my question is answered here:
Requirejs domReady plugin vs Jquery $(document).ready()?
The other answers here essential repeat what's in the above link. But, thanks!
I'm reading Addy Osmani's excellent blog post about writing AMD modules. I start with a simple chunk of js that I lifted from his post:
define('modTest', [],
// module definition function
function () {
// return a value that defines the module export
// (i.e the functionality we want to expose for consumption)
// create your module here
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
}
return myModule;
}
);
I took out the dependencies on foo and bar. Just want a simple object that logs to the console.
So I save that in /js/modTest.js and then try to load it:
curl(['/js/modTest.js'])
.then(function(mt) {
console.log("Load complete");
console.log("mt:");
console.log(mt);
mt.doStuff()
}, function(ex) {alert(ex.message);})
Result: error: Multiple anonymous defines in URL. OK that didn't work. Tried adding in a namespace: define('myCompany/modTest', [],, same result. Tried adding an empty string in the dependency array, same result.
Also tried curl(['modTest.js'], function(dep){console.log(dep)}); with the same result.
Is the code in Addy's blog post incorrect? Am I doing something wrong? Maybe a bug in curl?
Update 5/24: I ditched curl.js in favor of require.js. Zero odd errors, very little work to change over. I did have to deal with amdefine a bit to get my code running client and server side (one object is in both places, so grunt had to be configured to take care of that). My defines generally look like:
define(->
class AlphaBravo
...
And never have any trouble loading.
You asked curl() to fetch a module called "/js/modTest.js". It found the file and loaded it and found a module named "modTest", so it complained. :) (That error message is horribly wrong, though!)
Here's how you can fix it (pick one):
1) Remove the ID from your define(). The ID is not recommended. It's typically only used by AMD build tools and when declaring modules inside test harnesses.
2) Refer to the module by the ID you gave it in the define(). (Again, the ID is not recommended in most cases.)
curl(['modTest'], doSomething);
3) Map a package (or a path) to the folder with your application's modules. It's not clear to me what that would be from your example since modTest appears to be a stand-alone module. However, if you were to decide to organize your app's files under an "app" package, you packages config might look like this:
packages: [ { name: 'app', location: 'app' } ]
Then, when you have code that relies on the modTest module, you can get to it via an ID of "app/modTest".
curl(['app/modTest'], doSomething);
I hope that helps clear things up!
Fwiw, Addy's example could actually work with the right configuration, but I don't see any configuration in that post (or my eyes missed it). Something like this might work:
packages: [ { name: 'app', location: '.' } ]
-- John
I've just had a similar problem which turned out to be the include order I was using for my other libraries. I'm loading handlebars.js, crossroads.js, jquery and a few other libraries into my project in the traditional way (script tags in head) and found that when I place the curl.js include first, I get this error, but when I include it last, I do not get this error.
My head tag now looks like this:
<script type="text/javascript" src="/js/lib/jquery.js"></script>
<script type="text/javascript" src="/js/lib/signals.js"></script>
<script type="text/javascript" src="/js/lib/crossroads.js"></script>
<script type="text/javascript" src="/js/lib/handlebars.js"></script>
<script type="text/javascript" src="/js/lib/curl.js"></script>
<script type="text/javascript" src="/js/main.js"></script>
You have a problem with your define call. It is NAMED
See AMD spec for full story on how to write defines, but here is what I would expect to see in your js/modTest.js file:
define(/* this is where the difference is */ function () {
// return a value that defines the module export
// (i.e the functionality we want to expose for consumption)
// create your module here
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
}
return myModule;
}
);
Now, the boring explanation:
CurlJS is awesome. In fact, after dealing with both, RequireJS and CurlJS, I would say CurlJS is awesome-er than RequireJS in one category - reliability of script execution ordering. So you are on the right track.
On of the major things that are different about CurlJS is that it uses "find at least one anonymous define per loaded module, else it's error" logic. RequireJS uses a timeout, where it effectively ignores cases where nothing was defined in a given file, but blows up on caught loading / parsing errors.
That difference is what is getting you here. CurlJS expects at least one anonymous (as in NOT-named) define per loaded module. It still handles named defines fine, as expected. The second you move the contents of "js/modTest.js" into inline code, you will have to "name" the define. But, that's another story.
I have lots of functions and event handlers that are split across multiple javascript files which are included on different pages throughout my site.
For performance reasons I want to combine all of those files into 1 file that is global across the site.
The problem is I will have event handlers called on elements that won't necessarily exist and same function names.
This is an example of a typical javascript file...
$(document).ready(function(){
$('#blah').keypress(function(e){
if (e.which == 13) {
checkMap();
return false;
}
});
});
function checkMap() {
// code
}
function loadMap() {
// code
}
I would need to seperate this code into an object that is called on that specific page.
My thoughts are I could re-write it like this:
(function($) {
$.homepage = {
checkMap: function(){
// code
},
loadMap: function(){
//code
}
};
})(jQuery);
And then on the page that requires it I could call $.homepage.checkMap() etc.
But then how would I declare event handlers like document.ready without containing it in it's own function?
First of all: Depending on how much code you have, you should consider, if serving all your code in one file is really a good idea. It's okay to save http-requests, but if you load a huge chunk of code, from which you use 5% on a single page, you might be better of by keeping those js files separated (especially in mobile environments!).
Remember, you can let the browser cache those files. Depending on how frequent your code changes, and how much of the source changes, you might want to separate your code into stable core-functionality and additional .js packages for special purposes. This way you might be better off traffic- and maintainance-wise.
Encapsulating your functions into different objects is a good idea to prevent unnecessary function-hoisting and global namespace pollution.
Finally you can prevent calling needless event handlers by either:
Introducing some kind of pagetype which helps you decide calling only the necessary functions.
or
checking for the existence of certain elements like this if( $("specialelement").length > 0 ){ callhandlers}
to speed up your JS, you could use the Google Closure Compiler. It minifies and optimizes your code.
I think that all you need is a namespace for you application. A namespace is a simple JSON object that could look like this:
var myApp = {
homepage : {
showHeader : function(){},
hideHeader : function(){},
animationDelay : 3400,
start : function(){} // the function that start the entire homepage logic
},
about : {
....
}
}
You can split it in more files:
MyApp will contain the myApp = { } object, maybe with some useful utilities like object.create or what have you.
Homepage.js will contain myApp.homepage = { ... } with all the methods of your homepage page.
The list goes on and on with the rest of the pages.
Think of it as packages. You don't need to use $ as the main object.
<script src="myapp.js"></script>
<script src="homepage.js"></script>
<-....->
<script>
myApp.homepage.start();
</script>
Would be the way I would use the homepage object.
When compressing with YUI, you should have:
<script src="scripts.min.js"></script>
<script>
myApp.homepage.start();
</script>
Just to make sure I've understood you correctly, you have one js file with all your code, but you want to still be in control of what is executed on a certain page?
If that is the case, then the Terrific JS framework could interest you. It allows you to apply javascript functionality to a module. A module is a component on your webpage, like the navigation, header, a currency converter. Terrific JS scans the dom and executes the js for the modules it finds so you don't have to worry about execution. Terrific JS requires OOCSS naming conventions to identify modules. It's no quick solution to your problem but it will help if you're willing to take the time. Here are some more links you may find useful:
Hello World Example:
http://jsfiddle.net/brunschgi/uzjSM/
Blogpost on using:
http://thomas.junghans.co.za/blog/2011/10/14/using-terrificjs-in-your-website/
I would use something like YUI compressor to merge all files into one min.js file that is minified. If you are looking for performance both merging and minifiying is the way to go. http://developer.yahoo.com/yui/compressor/
Example:
Javascript input files: jquery.js, ads.js support.js
run yui with jquery.js, ads.js, support.js output it into min.js
Javascript output files: min.js
then use min.js in your html code.