We found Ext 2.2 starts to support literal config for TreeNode, AsyncTreeNode and TreeLoader. That helps us a lot and thank you!

Here is still a problem on AsyncTreeNode's TreeLoader. For example:

var tree = new Ext.tree.TreePanel({
xtype: 'treepanel',
el:'tree',
animate:true,
autoScroll:true,
containerScroll:true,
autoHeight: true,
loader: {dataUrl: "http://server/webapps/treePanel.jsp"},
root:
{
text: 'root2',
draggable:false, // disable root node dragging
loader: {dataUrl: "http://server/webapps/treeNode.jsp"},
id:'root',
expanded: true
}
});
tree.render();
});

"http://server/webapps/treeNode.jsp" never gets called. The same thing applies to all the children nodes. Even if they have different loader configured, Ext still uses TreePanel's loader to create the next level nodes.

Debug through the source codes, I found two suspicious places:

1. In TreeLoader.js
...
createNode : function(attr){
// apply baseAttrs, nice idea Corey!
if(this.baseAttrs){
Ext.applyIf(attr, this.baseAttrs);
}
if(this.applyLoader !== false){
attr.loader = this;

}
...

It seems like it doesn't honor node's own loader. what is "applyLoader" used for?

2. In AsyncTreeNode.js
Ext.tree.AsyncTreeNode = function(config){
this.loaded = config && config.loaded === true;
this.loading = false;
Ext.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
/**
* @event beforeload
* Fires before this node is loaded, return false to cancel
* @param {Node} this This node
*/
this.addEvents('beforeload', 'load');
/**
* @event load
* Fires when this node is loaded
* @param {Node} this This node
*/
/**
* The loader used by this node (defaults to using the tree's defined loader)
* @type TreeLoader
* @property loader
*/
};

It mentions the loader, but doesn't initialize it from "config", why?

I made two changes at these places and it seems make it work:
1.
...
if(this.applyLoader !== false){
attr.loader = attr.loader || this;
}
...

2.
...
var l = config.loader;
if(!l){
l = new Ext.tree.TreeLoader({
dataUrl: this.dataUrl
});
}else if(typeof l == 'object' && !l.load){
l = new Ext.tree.TreeLoader(l);
}
this.loader = l;
...

Not sure if these are right fixes though.