JavaScript/Dojo Module Pattern - how to debug? - javascript

I'm working with Dojo and using the "Module Pattern" as described in Mastering Dojo. So far as I can see this pattern is a general, and widely used, JavaScript pattern. My question is: How do we debug our modules?
So far I've not been able to persuade Firebug to show me the source of my module. Firebug seems to show only the dojo eval statement used to execute the factory method. Hence I'm not able to step through my module source. I've tried putting "debugger" statements in my module code, and Firebug seems to halt correctly, but does not show the source.
Contrived example code below. This is just an example of sufficient complexity to make the need for debugging plausible, it's not intended to be useful code.
The page
<!--
Experiments with Debugging
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>console me</title>
<style type="text/css">
#import "../dojoroot/dojo/resources/dojo.css";
#import "../dojoroot/dijit/themes/tundra/tundra.css";
#import "edf.css";
</style>
<script type="text/javascript" src="../dojoroot/dojo/dojo.js">
</script>
<script type="text/javascript" >
dojo.registerModulePath("mytest", "../../mytest");
dojo.require("mytest.example");
dojo.addOnLoad(function(){
mytest.example.greet();
});
</script>
</head>
<body class="tundra">
<div id="bulletin">
<p>Just Testing</p>
</div>
</body>
</html>
<!-- END: snip1 -->
The java script I'd like to debug
dojo.provide("mytest.example");
dojo.require("dijit.layout.ContentPane");
/**
* define module
*/
(function(){
//define the main program functions...
var example= mytest.example;
example.greet= function(args) {
var bulletin = dojo.byId("bulletin");
console.log("bulletin:" + bulletin);
if ( bulletin) {
var content = new dijit.layout.ContentPane({
id: "dummy",
region: "center"
});
content.setContent('Greetings!');
dojo._destroyElement(bulletin);
dojo.place(content.domNode, dojo.body(), "first");
console.log("greeting done");
} else {
console.error("no bulletin board");
}
}
})();

(Answering this myself because it seems like a common problem whose solution is not well known.)
It seems that one can nicely debug eval-ed code in FireBug provided that dojo does a little cooperating. The trick is to configure dojo to enable such debugging using debugAtAllCosts
<script type="text/javascript" src="/dojoroot/dojo/dojo.js"
djConfig="parseOnLoad: true, debugAtAllCosts: true"></script>
This is described on dojo campus under debugging, which also notes that this setting is not recommended in production for performance reasons and suggests an approach using server-side conditionality to control whether such debugging is enabled.

Also, if you are using a version of Firebug less than 1.7a10 also verify that you have the "Decompile for eval() source" on the scripts drop-down disabled (extensions.firebug.decompileEvals in about:config). When enabled I think this causes Firebug to overwrite the source with its own decompiled version and somehow lose the filename along the way as well.
#peller, This could be why your answer wasn't working for us.
It's disabled by default, but I turned it on at some point and didn't realize it.
It's also being removed completely in 1.7a10 as part of Firebug issue http://code.google.com/p/fbug/issues/detail?id=4035. Also related discussion at https://groups.google.com/d/topic/firebug/y2VR17IFHHI/discussion and https://groups.google.com/d/topic/dojo-interest/nWlZdJDlic8/discussion.

Here's a solution I found for the inability to recurse into dojo.require mudules from reading the NGs.
Change
<script src="dojoroot/dojo/dojo.js" type="text/javascript">
to
<script src="dojoroot/dojo/dojo.js.uncompressed.js" type="text/javascript">
This fixes the less than helpful
undefineddojo._scopeArgs = [undefined];
error that one sees otherwise.

The pattern is essentially xhr+eval... really it's the eval that's the problem... Firefox in particular has no way to track code from an eval back to its original source and instead points at the eval call site, plus whatever line offset there is in the eval buffer. Firebug has implemented a clever scheme to workaround this problem, and added an optional hint which loaders like Dojo can use to embed the original file path in a comment. Webkit now supports this scheme also. It's not perfect, but debugger; and other breakpoints ought to bring you into the correct buffer.
I'm not sure why none of this would be working for you. Which version of Firebug are you using?

djna's debugAtAllCosts solution works for me, for the reasons described at http://dojotdg.zaffra.com/tag/dojorequire/.
However, note that using debugAtAllCosts causes dojo.require to become asynchronous because it uses script inserts rather than xhr+eval. This can cause problems with code that expects dojo.require to be synchronous that isn't brought in using require itself (as described at http://kennethfranqueiro.com/2010/08/dojo-required-reading/). In my case it was testing code I had being run by unit test framework. So the following failed saying that EntityInfo was not defined
var e1 = new EntityInfo();
until I changed it to
dojo.addOnLoad(function() {
var e1 = new EntityInfo();
}
#peller, For me FireBug 1.6.1 will take me to the right eval block but not the right file and line numbers (because its an eval string rather than the original file)..

I'll add one more alternative, use Chrome. It's great for debugging evals (seems to catch some things Firebug doesn't). Do be aware of its issue with caching JS files - http://code.google.com/p/chromium/issues/detail?id=8742.
Personally Firebug is still my main environment, but I am now also using Chrome when things get tricky with evals to get a second view at the problem. Chrome helped me twice yesterday with undefined function/variable issues with the dojo loader that Firebug skipped right past).

Related

How to bring back Javascript syntax error detection in Visual Studio Code

Take the following sample of HTML.
<html>
<head>
<script>
var myArr = ['thing1' thing2'];
</script>
</head>
<body>
</body>
</html>
If you're perceptive, you'll notice that I forgot to put a comma between the two array values inside of the script. This will, of course, cause any browser to fail to parse it and the whole script tag will not run. In previous versions of Code, this would be noted with a red underline, but it seems like in recent versions support has moved to plugins. They recommend installing the JSHint plugin to catch some issues, but I have a .jshintrc file in my project directory, with very few entries (to try to use mostly defaults) and while it catches "recommendations", it's still not catching actual syntax issues that break the scripts entirely. I'm also not sure it's doing anything for JavaScript it sees inside of a <script> tag (which I currently use to do quick tests or examples of features). It highlights keywords, but doesn't check syntax or anything.
Is there any configuration I can apply to Code, or my project, to get back this behavior?
The catching of actual syntax issues has been delegated to the Salsa interpreter within Visual Studio. Maybe this is a bug? However, for the other point you made about quick-checking code within script tags, as of the v0.10.10 Feb 2016 release notes:
There is no longer support for IntelliSense in script sections inside HTML documents.

Hiding JavaScript from displaying in old browsers

I am trying to learn JavaScript from a book. The first chapter of the book says to use the following format to support older browsers that don't support JS. What it actually does is simple, it uses HTML comment tag to hide script from browsers that don't support JS. My doubt here is this code works fine for me in all the browsers but is showing error in Aptana Studio 3. Now I understand that the error is due to Aptana considering "<" as a relational operator but how can I resolve this error?
<script>
<!--
//some JS code over here...
//-->
</script>
Error(Syntax Error: Unexpected Token) coming at :
<!--
I'm aware that this does not answer your question directly, but the truth is that this simply does not need to be done. If a browser does not know how to interpret the JavaScript, almost all browsers will ignore the code anyway. Furthermore, adding the <!-- // --> can be dangerous as well for the following reasons, given by Matt Kruse:
Within XHTML documents, the source will actually be hidden from all browsers and rendered useless
It is not allowed within HTML comments, so any decrement operations in script are invalid
For a more detailed explanation, I recommend you check out this documentation about the best practices for JavaScript and this question that explains why using HTML comments in JavaScript is bad practice.
If for whatever reason you still want to show content to the user if they have JavaScript disabled (or can't run it because of an old browser), use a <noscript> tag
If you truly are deadset on commenting out your JavaScript then use this code snippet instead, which shouldn't give you the error:
//<!--
//-->
If you have any more questions feel free to ask.
Every browser now supports JS. This trick was used to prevent the first generation browsers from showing JS code as plain text.
You may wanna take a look at this article.
Do not use the <!-- //--> hack with scripts. It was intended to prevent scripts from showing up as text on the first generation browsers Netscape 1 and Mosaic. It has not been necessary for many years. <!-- //--> is supposed to signal an HTML comment. Comments should be ignored, not compiled and executed. Also, HTML comments are not to include --, so a script that decrements has an HTML error.
Edit 1:
If you still wanna use this trick in Aptana Studio 3 try commenting the first part too:
<script>
//<--
Code Goes Here...
//--!>
</script>
I didn't test but solved the error in aptana

Firebug not listing all javascript modules

I'm having a problem getting Firebug (and Chrome) to list the javascript files/modules that I've defined and included. I've recently switched from Dojo 1.5 to Dojo 1.9.1 AMD and am including the javascript modules through the require protocol as designed. This had been working fine until just recently when I changed the Dojo configuration's "async:true" to "async:false" in order to support some legacy code that still needs the "dojo.require" to be recognized and supported. Changing the Dojo configuration to "async:false" allowed the "dojo.require" calls to work, but somehow broke the ability of Firebug and Chrome to "see" the loaded javascript modules. I just temporarily switched the config back to "async:true" to verify that Firebug successfully listed the javascript modules so it is definitely the cause of the effect.
The functionality of the JSP pages still appear to behave as expected - so the javascript modules are being included as needed, but when I try to view them and set breakpoints in them from Firebug - they are not listed. If I search for a particular string that appears in one of them, then Firebug will successfully find the javascript code but shows that it is "located" under the heading of something like:
/dojo/1.9.1/dojo/dojo.js.uncompressed.js line 328 > Function line 1 > eval (2)
instead of the actual file/module name. I'm unable to set breakpoints from this view, but if I add a "debugger;" line into the javascript file then Firebug will stop at that location during execution - not an ideal workaround.
Any idea why switching from "async:true" to "async:false" would cause this behavior in Firebug?
Thanks. Any help is appreciated.
You have to add has:{'dojo-firebug': true } to your dojoConfig like this:
<script type="text/javascript">
var dojoConfig = {
has: {
'dojo-firebug': true
}
};
</script>
You can also add it in like this:
<script type="text/javascript"
src="your_dojo_src_path_here"
data-dojo-config="has:{'dojo-firebug':true}">
</script>

which javascript files are NOT being used on page load

Is it possible to find out which javascript files are NOT used on a web page without having to add console logs or debug or removing them to see if things break?
I'm looking for a tool, or a command line script or firefox plugin etc.
For example, let's say I have these included in the header:
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/functions.js"></script>
<script type="text/javascript" src="js/validation.js"></script>
<script type="text/javascript" src="js/something.js"></script>
On the page, calls are only made to functions in functions.js, validation.js and jquery.js. How can I know that something.js is not used and therefore can be safely removed from the header?
I've tried rooting through things like FireBug, chrome's console, yslow and server logs, but these all tell me which scripts have been loaded, i.e. all of them, not which ones have been used.
AFAIK there is no simple "this file is in use / not in use" detection mechanism, because there are so many ways to call, extend and reference things in JavaScript.
There are dozens of ways to call a function, e.g. in the click event of an element, eval() statements... You could be extending the prototype of an existing class in a script file... etc. Also, you could be fetching new markup through AJAX than in turn references functions from a certain include, something impossible to test for automatically without fetching the content.
Unless somebody comes up with a tool that tackles exactly this (I'm not saying it's impossible, just that it is horribly hard) I'd say working this out manually with a good IDE and search function is the best way to go about it.
In answer to my own question getting on for 7 years later, Chrome dev tools now has exactly this feature! https://developers.google.com/web/updates/2017/04/devtools-release-notes#coverage
Only took 7 years :) Also wanted to point out that you can automate this with Navalia: https://github.com/joelgriffith/navalia.
Here's a quick example:
import { Chrome } from 'navalia';
const chrome = new Chrome();
async function checkCoverage() {
await chrome.goto('http://joelgriffith.net/', { coverage: true });
const stats = await chrome.coverage('http://joelgriffith.net/main.bundle.js');
console.log(stats); // Prints { total: 45913, unused: 5572, percentUnused: 0.12135996340905626 }
chrome.done();
}
checkCoverage();
More here https://joelgriffith.github.io/navalia/Chrome/coverage/.
Coming at this from a different direction, you could look into using (lazy) loading javascript libraries. I couldn't say how appropriate this would be in your situation, but I have seen mention of these two in the last week, but haven't used either of them:
http://plugins.jquery.com/project/lazy (only for lazy loading of jQuery plugins?)
http://labjs.com/ (not sure if this does lazy loading?)

jQuery $(document).ready() failing in IE6

I have the following code:
// Creates a timer to check for elements popping into the dom
timer = setInterval(function ()
{
for (p in pixelTypes)
{
checkElems(pixelTypes[p]);
}
}, 10);
// Add Document finished callback.
$(document).ready(function ()
{
// Document is loaded, so stop trying to find new pixels
clearInterval(timer);
});
In Firefox, it works great, but in IE6, I get a "Object Expected" error on the $(document).ready line.
I can't figure out what would cause IE6 to not recognize it, jquery is fully loaded by this point.
Is this a known issue?
Just a few pointers for anyone that's interested:
$(document).ready(function() {...}); and $(function() {...}); means exactly the same thing. The latter is a shorthand for the former.
If you develop for a large site, using multiple Javascript libraries, or you develop plugins meant to be compatible with other peoples work, you can not trust the dollar sign ($) to be associated with the jQuery object. Use the following notation to be on the safe side:
(function($) { [your code here] })(jQuery);
This passes jQuery into a self-executing function, and associates $ with the jQuery object inside this function. Then it does not matter what the $ represents outside of your function.
To get back to your question, have you checked whether the timer variable is assigned when you get the error? I believe the browser will see the $(document).ready(function() {...}); all as one line, so if you have some kind of debugger that tells you that's the offending line, it might be the timer variable...
Last thing: In Javascript, it is not correct to place open curly braces on a new line. This can cause really bad errors due to Javascripts semicolon-insertion. For further info, read Douglas Crockford's Javascript: The good parts:
http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=sr_1_1?ie=UTF8&s=books&qid=1267108736&sr=1-1
Anyway, really hope I didn't upset anyone. Hope you solve the problem!
EDIT: I'm not sure if this is what robertz meant by fully qualified, but as far as I know, when a URL is fully qualified it means no parts are missing, ie. it's an absolute URL starting with http:// or https:// (or some other protocol).
Please correct me if I'm wrong!
I've had this same issue in the past too. It was a sporadic issue and was horrible to and reproduce.
The solution that I found was to replace $(document).ready(function() {...}); with jQuery(function() {...}) and it worked like a charm!
Moving $(document).ready(function() {...}); to the bottom didn't work for my use case.
The comments in this post are incredibly helpful (Where I first read about doing it this way)
If anyone have the same problem you should see if when you call your javascripts you have type="application/javascript", I eliminate it and it was corrected, I think it's some problem with IE and the type Thing
Are you sure that jQuery is loaded? Try debugging with alerts like:
alert(typeof $);
You could also try a different syntax:
$(function() {
clearInterval(timer);
});
Ok, so from your comment, the above doesn't help. The "object expected" error seems to occur with a syntax error in my experience. Is that the exact code you've got? If not, could you post it?
Make sure your script type is text/javascript
<script type='text/javascript'
The DateTime picker worked just fine on my local XP test, but it failed "Object Expected" once deployed on the server. After 2 days of being persistent, this is how I solved my problem, adding the Url.Content around the path of the Javascript!
<script src="<%= Url.Content("~/Scripts/jquery-1.4.1.min.js") %>" type="text/javascript"></script>
<script src="<%= Url.Content("~/Scripts/ui/minified/jquery.ui.core.min.js") %>" type="text/javascript"></script>
<script src="<%= Url.Content("~/Scripts/ui/minified/jquery.ui.datepicker.min.js") %>" type="text/javascript"></script>
I don't think that you should really be polling for elements the way you are.
The document ready event calls as soon as the browser has loaded enough for you to be able to manipulate the page, so you should just do your DOM processing in the $(document).ready() block.
You could try the old skool way of checking whether the document is "ready"... Place the script just before the closing </body> tag - I believe it has the same effect as jQuery's 'ready' event - actually, it's probably quicker doing it this way.
In my experience the "Object expected" error in IE6 shows up because of a syntax error - it's worth putting the script though JSlint, if you haven't already...
I ran into this problem on my machine, as was able to find a quick fix. Here's what I did:
1.Debugged my javascript with nickf's suggestion "alert(typeof $)" and got the "undefined" alert message
2.I then fully qualified my jQuery script resources.
3.Reload my page and received the "function" alert message
BTW, I am using IIS 5.1 on XP. My website is configured to use "Wildcard mapping" to take advatage of the asp.net mvc framework. I think that this configuration caused the broken links.
For more information on how to setup MVC on old versions of IIS, check out Phil Haack's post:
http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx
$(document).ready() tells you when the dom is ready, but not all assets are necessarily done coming in.
If you want to make sure all the assets are actually done loading, use $(window).load() instead. The most common use for this is to make sure that images are done loading, but it may work for your script problem as well.
If it is in a script element which is within your body element, (i.e.) ..
The cause can be the attributes you pass with the script-tag. If it is:
<script type="text/javascript">...</script>
IE6 can give an error. You should use
<script language="javascript">...</script>
Then the error goes away.
I had the same issue, script error informing me that the object was undefined. I tried all the suggestions listed here with no avail. Only thing I did not consider was security, I had forgotten all about my forms authentication and turns out I forgotten about the authorisation on the scripts folder which was denying access to the jQuery libraries!!!
Hope this helps.

Categories

Resources