Monday, October 1, 2007

JavaScript debugging in Firefox extensions

I've been working on a few Firefox extensions. One of the most difficult things I found was a good way to debug JavaScript code.

Starting out by reading MDC's "Setting up extension development environment" page is a great first step. Enabling the javascript.options.showInConsole and javascript.options.strict options are a good help. Also enabling nglayout.debug.disable_xul_cache and browser.dom.window.dump.enabled doesn't hurt anything, though I don't consider these options as useful.

Of the listed "helpful extensions", JavaScript Debugger, a.k.a. "Venkman" is definitely the most useful. It took me a few minutes how to set the scope to the browser window: Find the "Open Windows" view, right-click on "Browser Window", and select "Set as Evaluation Object".

DOM Inspector

The DOM Inspector, sometimes a.k.a. "DOMi" is great for inspecting the Chrome layout.

For Firefox 2.x, this is not a separate extension. Choose to install with a Firefox custom install. For Firefox 3.x, it is available at https://addons.mozilla.org/en-US/firefox/addon/6622. (See also bug 339229 and bug 271812 for details on the move.)

The DOM Inspector can also be used for inspecting the JavaScript of the ChromeWindow in a pinch, though it's not readily apparent how. (The lack of any real documentation doesn't help much.) "Mossop" was kind enough to help me out at irc.mozilla.org#extdev by pointing me to the defaultView property. In summary:

  1. Open DOM Inspector
  2. Select the "#document" nodeName from the left-hand pane.
  3. Select to inspect the "Javascript Object" using the drop-down above the right-hand pane.
  4. Expand "Subject", then "defaultView".

JavaScript can then be executed on defaultView or any children by right-clicking on the desired property, and choosing "Evaluate JavaScript...".

Unfortunately, in Firefox 2.x, the property tree is not sorted. This was fixed with bug 226819, but isn't included until the 2.0.0 version for Firefox 3.x. (The defaultView was broken in Firefox 3.0a8 in that it won't expand. I had reported this in bug 398285.)

Console2 and Chrome List are also useful and recommended. The Extension Developer's Extension may prove useful to some - though I'm not currently one of them.

Firebug

I do think that Firebug is a great extension, but it's main use is mostly focused on debugging and analyzing loaded web pages within the main browser window, rather than the Firefox browser itself (i.e., the Chrome). An interesting hack is to open chrome://browser/content/browser.xul as a web page. This essentially opens an instance of Firefox from inside the browser window. (See "Fun with Firefox Chrome URLs".) Unfortunately, this can cause a number of side effects, particularly with various add-ons. (Read more at Issue 194 - Firebug should be able to inspect chrome and "Firebug and Firefox".)

Stack Traces

The other issue I had was finding stack traces, or at least the source file and line number of an error. Most of this seems to come naturally for debugging web pages with Firebug, but can be trickier to track down within a Firefox extension.

As listed above, upgrading to the Console2 is a good upgrade to and even fixes a few bugs with Firefox's built-in "Error Console". Unfortunately, it still doesn't display all of the available debugging information from a JavaScript error. See the FAQ at http://console2.mozdev.org./ as well as Mozilla bugs 228205 and 125612 for details.

The first thing to check is that the only unhandled objects being thrown are based on the global Error object. Unlike Java, where only an instance of a class extending Throwable can be thrown, JavaScript allows any instance of an object to be thrown. I.E., throwing a string, e.g. throw "This is an error!" is completely valid. However, only objects built from the Error object contain the populated details, e.g. fileName, lineNumber, and stack.

Even with Console2 installed and throwing Error objects, I still find the following helpful - at least until Firefox/Console2 supports the Error's stack by default:

try{
  // Do, or call to, all your code here.
}catch(e){
  try{
    if(e.stack){
      Components.utils.reportError(e.stack);
    }
    // Show the error console.
    toJavaScriptConsole();
  }finally{
    throw e;
  }
}

This will actually generate seemingly duplicate messages to the console: first one with the additional detail, then the one that would be generated by default - but I find that it's the safest way, and still allows for showing non-Error objects that were thrown by the default method.

While I'm on the topic, before continuing work on your next extension, please also read Respecting the JavaScript global namespace.

Updated: 2007-10-09, 2008-05-13 - Information on DOM Inspector

4 comments:

Anonymous said...

I am struggling with debugging JavaScript in Firefox extensions too. Your article is helpful to me, thanks! Have you tried Aptana, it an IDE that supports JavaScript editing and debugging.

Joe said...

Hi

I have a JavaScript code, Is there any method,.. to temporary pause the code and then resume it?

Here is sample:
var b = 2;
some_async_function_call();
/*Some asynchronous call which resume code after finishing job; */

/**breakpoint here; something like debugger keyword,... **/

alert (b);

/*This function will be called from asynchronous call*/
var resume_function = function() {
// Resume main code by sending something to resume from pause point;
}



P.S: I am working on FF.
Do you have any idea how can I implement it?

LeslieM said...

Re: debugging JavaScript in Firefox extensions


Check out ChromeBug. Per the GetFireBug wiki - "Chromebug is Firebug for XUL applications, especially Firefox extensions. We use Chromebug to debug Firebug!
". "Chromebug is 100% XUL/HTML/CSS/Javascript and works only on XUL based applications."

See http://getfirebug.com/wiki/index.php/Chromebug_User_Guide

Amir Harel said...

Thanks for the post. i read it when i tried to find a good way to debug my firefox extension.

I also wrote a post about writing debug messages to a local file in order to help debug extension on a client machine.

http://www.amirharel.com/2010/02/21/debugging-firefox-extension-using-log-file/