Breaking and busting

At some point in the development of a project, a developer will inevitably be faced with an obscure error, which is raised from the depths of Ext JS when the application loads. This raises an issue with the way Ext JS sets up its caching mechanism. For example, a normal (if slightly naïve) request for a JavaScript file might look like this:

GET: /assets/javascripts/jquery.min.js

Out of the box, Ext.Loader will pull scripts like this:

GET: /ext/build/ext-all-rtl-debug.js?_dc=1420215165267

It appends a timestamp query variable to the request. This is designed to ensure that we always get the latest version of the script by bypassing browser caching mechanisms.

This can be very useful; however in our situation, it means that any breakpoints set in our code will be removed when the page reloads because Chrome thinks the file is different as the timestamp's different.

How can we resolve this? It turns out to be really simple; just open app.json in the root of an Ext JS project and search for the comment starting "this option is used to configure the dynamic loader". The comment contains various options to be passed to the loader, such as passing true, which "allows requests to receive cached responses". So, we can add the following code:

"loader": {
        "cache": true
},

Also, the cache-busting timestamps will be removed. Note the trailing comma. This is required to ensure the file remains as parsable JSON.

Caught in the act

Back to the situation in which errors pop up to surprise us. There may be an error that happens on page load, on user interaction, or because of some background job. It would be great to be able to catch errors as they happens so that we can poke around with the debugger and try and establish what went wrong.

Fortunately, Chrome provides a feature that does exactly this: "break on error", as shown here:

Caught in the act

The "break on error" icon, highlighted by a red circle

Let's try a contrived example. Click on the "break on error" button and it turns blue, then open up the Alcohology project's Application.js file, and add the following code to the launch method:

Ext.create('Ext.Panel', {
    html: 'Break on error test!',
    renderTo: 'myElement'
});

Save and reload the web browser. Chrome will immediately jump to the source of the error deep into the Ext JS code:

Caught in the act

Chrome's debugged paused on a line of code which is throwing an error

The original error thrown is Uncaught TypeError: Cannot read property 'dom' of null. This doesn't make much sense out of context. Now that we're in the code, we can see the surrounding variables and work out exactly what was null, in this case, the el variable.

We can also use the Call Stack panel in the right-hand pane to jump up through the call stack to the code that originally initiated this code path and view all of the code calls in between. This is great in complicated scenarios to let us trace the root source of an error:

Caught in the act

Alone, none of this will help us solve the problem. Being able to see the error, the state of the application when it was raised, and the path through the code to the original call site, all in combination with an understanding of Ext JS and a bit of intuition give us a smoking gun to resolve this issue.

The el variable, short for "element" is null, and looking back at our code in the launch method shows that we set our panel to renderTo an element called myElement. Using the Call Stack pane, we can step down to the constructor and do some detective work:

  • Ext.create will call the constructor for the panel; we can see this by clicking on Ext.panel.Panel in the Call Stack pane.
  • This in turn calls the render method on the Ext.util.Renderable mixin. It passes the value of the renderTo config as an argument.
  • Within the render method, this argument is called container.
  • The render method calls Ext.DomHelper.append with a container argument, which the debugger shows to be null.
  • This indicates that the container variable is being manipulated elsewhere within the render method.
  • Tracing back, we find the culprit: container = me.initContainer(container).
  • The initComponent contains the line container.dom ? container : Ext.get(container).

All of this leads us to the root source of this particular error: the string myElement is passed to Ext.get. As we haven't added an element with this ID to the HTML page, Ext JS cannot find it. This means that the panel doesn't have a valid container to render to and causes an error to be thrown.

The ability to undertake this kind of investigation can be the difference between a project that meets its deadlines and one that stalls due to unexpected issues. Diving deep into the code in this way is an essential skill to avoid roadblocks and keep your developers moving.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset