We don't have Sencha Cmd in the Firm (I guess for licencing reasons), but it's also a wise idea not to use ext-all/ext-all-debug, but just ext.js (or ext-debug.js and minify later). But this is a little tricky, because ext.js will load core dependencies dynamically. Now we wanted to bundle it for production, for which the order of the files during the concatenation is critical. Ext.Loader.history and Ext.manifest contains all the necessary ordering information, but unfortunately ext.js contains some "override" classes, which reference yet undefined dependencies. This means that these dep classes inevitably get loaded dynamically. This is a huge surprise actually, because these "override" classes are in the right position in ext-all.
Any information from Ext devs, why is it this way?
We actually worked around the problem with a premature Ext.define override which delays class definition processing until all the necessary classes are defined for the given class.
This way a bundled app can easily go below 2 MB, while ext-all.js itself is 2.3 MB.
Here is the script btw, should anyone be interested:
--------------
Code:
/**
* This is a pre-extjs utility snippet which fixes to-be-loaded unbundled Ext JS in
* synchronous mode (flattened/concatenated). Yes, it has to be used _before_ Ext JS is loaded.
* It sets up a pre-made empty Ext object with a setter on 'define', so we can hook up.
* It delays Ext.define() calls until all the dependencies of the given class have already been defined.
* It solves the problem that unbundled ext(-debug).js contains unresolved dependencies in its Ext.overrides.*
* definitions. In other words: it ensures the correct order of Ext.define() invocations,
* given that loading/defining all the necessary classes (in any order) is ensured.
*/
/* eslint-disable */
(function(window) {
// quick util replacements for lodash functionality.
const castArray = val => val instanceof Array ? val : [val];
const values = obj => obj && Object.keys(obj).map(key => obj[key]);
const negate = pred => (...args) => !pred(...args);
// extract wildcarded deps (like 'Ext.data.operation.*')
const extractDep = depName => {
const re = new RegExp(depName.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$');
return Object.keys(Ext.manifest.classes).filter(clsName => re.test(clsName));
};
// get dependencies for a given class descriptor.
const getDeps = clsData => [
clsData.extend,
clsData.override,
...castArray(clsData.requires),
...castArray(values(clsData.mixins))
]
.filter(dep => typeof dep === 'string') // filter out undefineds and already resolved object deps
.reduce((cum, next) => [...cum, ...extractDep(next)], []);
const notDefined = clsName => !Ext.ClassManager.get(clsName);
const hasDep = node => node.deps.length;
const hasNoDep = negate(hasDep);
const cleanupNodes = nodes =>
nodes.forEach(node => {
node.deps = node.deps.filter(notDefined);
});
let nodes = [];
const overrideDefine = originalDefine =>
function(clsName, data) {
const undefinedDeps = getDeps(data).filter(notDefined);
if (undefinedDeps.length) {
nodes.push({ args: arguments, deps: undefinedDeps });
} else {
const result = originalDefine(...arguments);
cleanupNodes(nodes);
while (nodes.some(hasNoDep)) {
nodes.filter(hasNoDep).forEach(
node => originalDefine(...node.args)
);
nodes = nodes.filter(hasDep);
cleanupNodes(nodes);
}
return result;
}
};
let overridenDefine;
window.Ext = Object.defineProperty({}, 'define', {
set(define) {
overridenDefine = overrideDefine(define.bind(this));
},
get() {
return overridenDefine;
}
});
})(window);