13693261870
2022-09-16 354b3dbfbffb3df45212a2a44dbbf48b4acc2594
1
Ext.data.JsonP.command_code({"title":"Compiler-Friendly Code Guidelines","guide":"<h1>Compiler-Friendly Code Guidelines</h1>\n<div class='toc'>\n<p><strong>Contents</strong></p>\n<ol>\n<li><a href='#!/guide/command_code-section-1'>What The Compiler Is Not</a></li>\n<li><a href='#!/guide/command_code-section-2'>Framework Awareness</a></li>\n<li><a href='#!/guide/command_code-section-3'>Code Organization</a></li>\n<li><a href='#!/guide/command_code-section-4'>Class Declaration</a></li>\n<li><a href='#!/guide/command_code-section-5'>Overrides</a></li>\n<li><a href='#!/guide/command_code-section-6'>Conclusion</a></li>\n</ol>\n</div>\n\n<p>One of the major components new to V3 of Sencha Cmd is the compiler. This guide tells you\nall about how to write code that gets the most out of the compiler today, but also to help\nyour code base immediately benefit from the framework-aware optimizations that we have\nplanned for future releases.</p>\n\n<p><p><img src=\"guides/command_code/../command/sencha-command-128.png\" alt=\"\"></p></p>\n\n<h2 id='command_code-section-1'>What The Compiler Is Not</h2>\n\n<p>For starters, it is important to explain that th Sencha Cmd compiler is <strong>not</strong> a replacement\nfor tools like these:</p>\n\n<ul>\n<li><a href=\"http://developer.yahoo.com/yui/compressor/\">YUI Compressor</a>.</li>\n<li><a href=\"https://developers.google.com/closure/compiler/\">Google Closure Compiler</a>.</li>\n<li><a href=\"https://github.com/mishoo/UglifyJS/\">UglifyJS</a>.</li>\n</ul>\n\n\n<p>These tools solve different problems for JavaScript developers in general. These tools are\nvery good at the world of JavaScript but have no understanding of Sencha framework features\nsuch as <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a></code> for declaring classes.</p>\n\n<h2 id='command_code-section-2'>Framework Awareness</h2>\n\n<p>The role of the Sencha Cmd compiler is then to provide framework-aware optimizations and\ndiagnostics. Once code has passed through the Sencha Cmd compiler, it is ready to go on\nto more general tools like the above.</p>\n\n<p>In early testing, these kinds of optimizations have shown to significantly improve \"ingest\"\ntime of JavaScript code by the browser... especially on legacy browsers.</p>\n\n<p>In order for the compiler to provide these benefits, however, it is now important to look\nat coding conventions that it can \"understand\" and therefore optimize for you. Following\nthe conventions described in this guide will ensure that your code is positioned to get\nthe most from Sencha Cmd today and in the future.</p>\n\n<h2 id='command_code-section-3'>Code Organization</h2>\n\n<p>The dynamic loader and the previous JSBuilder have always made certain assumptions about\nhow classes are organized, but they were not seriously impacted by failure to follow those\nguidelines. These guidelines are very similar to Java.</p>\n\n<p>To recap, these guidelines are:</p>\n\n<ul>\n<li>Each JavaScript source file should contain one <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a></code> statement at global scope.</li>\n<li>The name of a source file matches the last segment of the name of the defined type (e.g.,\nthe name of the source file containing <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>(\"MyApp.foo.bar.Thing\", ...</code> would be\n\"Thing.js\".</li>\n<li>All source files are stored in a folder structure that is based on the namespace of the\ndefined type. For example, given <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>(\"MyApp.foo.bar.Thing\", ...</code>, the source file\nwould be in a path ending with \"/foo/bar\".</li>\n</ul>\n\n\n<p>Internally, the compiler views source files and classes as basically synonymous. It makes\nno attempt to split up files to remove classes that are not required. Only complete files\nare selected and included in the output. This means that if any class in a source file is\nrequired, all classes in the file will be included in the output.</p>\n\n<p>To give the compiler the freedom to select code at the class-level, it is essential to put\nonly one class in each file.</p>\n\n<h2 id='command_code-section-4'>Class Declaration</h2>\n\n<p>The Sencha Class System provides the <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a></code> function to enable higher-level, object\noriented programming. The compiler takes the view that <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a></code> is really a form of\n\"declarative\" programming and processes the \"class declaration\" accordingly.</p>\n\n<p>Clearly if <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a></code> is understood as a declaration, the content of the class body cannot\nbe constructed dynamically in code. While this practice is rare, it is valid JavaScript.\nBut as we shall see below in the code forms, this is antithetical to the compiler's\nability to understand the code is parses. Dynamic class declarations are often used to do\nthings that can better be handled by other features of the compiler. For more on these\nfeatures, see the <a href=\"#/guide/command_compiler\">Sencha Compiler Reference</a>.</p>\n\n<p>The compiler understands the \"keywords\" of this declarative language:</p>\n\n<ul>\n<li><code>requires</code></li>\n<li><code>uses</code></li>\n<li><code>extend</code></li>\n<li><code>mixins</code></li>\n<li><code>statics</code></li>\n<li><code>alias</code></li>\n<li>`singleton</li>\n<li><code>override</code></li>\n<li><code>alternateClassName</code></li>\n<li><code>xtype</code></li>\n</ul>\n\n\n<p>In order for the compiler to recognize your class declarations, they need to follow one of\nthe following forms.</p>\n\n<h3>Standard Form</h3>\n\n<p>Most classes use simple declarations like this:</p>\n\n<pre><code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>('Foo.bar.Thing', {\n    // keywords go here ... such as:\n\n    extend: '...',\n\n    // ...\n});\n</code></pre>\n\n<p>The second argument is the class body which is processed by the compiler as the class\n\"declaration\".</p>\n\n<p><strong> In all forms, <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a></code> should be called at global scope. </strong></p>\n\n<h3>Wrapped Function Forms</h3>\n\n<p>In some use cases the class declaration is wrapped in a function to create a closure scope\nfor the class methods. In all of the various forms, it is critical for the compiler that\nthe function end with a <code>return</code> statement that returns the class body as an object\nliteral. Other techniques are not recognized by the compiler.</p>\n\n<h4>Function Form</h4>\n\n<p>To streamline the older forms of this technique described below, <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a></code> understands\nthat if given a function as its second argument, that it should invoke that function to\nproduce the class body. It also passes the reference to the class as the single argument\nto facilitate access to static members via the closure scope. Internally to the framework,\nthis was the most common reason for the closure scope.</p>\n\n<pre><code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>('Foo.bar.Thing', function (Thing) {\n\n    return {\n        // keywords go here ... such as:\n\n        extend: '...',\n\n        // ...\n    };\n});\n</code></pre>\n\n<p><strong>NOTE:</strong> This form is only supported in Ext JS 4.1.2 and Sencha Touch 2.1 (or newer).</p>\n\n<h4>Called Function Form</h4>\n\n<p>In previous releases, the \"Function Form\" was not supported, so the function was simply\ninvoked immediately:</p>\n\n<pre><code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>('Foo.bar.Thing', function () {\n\n    return {\n        // keywords go here ... such as:\n\n        extend: '...',\n\n        // ...\n    };\n}());\n</code></pre>\n\n<h4>Called-Parenthesized Function Form</h4>\n\n<p>This form and the next are commonly used to appease tools like JSHint (or JSLint).</p>\n\n<pre><code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>('Foo.bar.Thing', (function () {\n\n    return {\n        // keywords go here ... such as:\n\n        extend: '...',\n\n        // ...\n    };\n})());\n</code></pre>\n\n<h4>Parenthesized-Called Function Form</h4>\n\n<p>Another variation on immediately called \"Function Form\" to appease JSHint/JSLint.</p>\n\n<pre><code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>('Foo.bar.Thing', (function () {\n\n    return {\n        // keywords go here ... such as:\n\n        extend: '...',\n\n        // ...\n    };\n}()));\n</code></pre>\n\n<h3>Keywords</h3>\n\n<p>The class declaration in its many forms ultimately contains \"keywords\". Each keyword has\nits own semantics, but there are many that have a common \"shape\".</p>\n\n<h4>Keywords using String</h4>\n\n<p>The <code>extend</code> and <code>override</code> keywords only accept a string literal.</p>\n\n<p>These keywords are also mutually exclusive in that only one can be used in any declaration.</p>\n\n<h4>Keywords using String or String[]</h4>\n\n<p>The following keywords all have the same form:</p>\n\n<ul>\n<li><code>requires</code></li>\n<li><code>uses</code></li>\n<li><code>alias</code></li>\n<li><code>alternateClassName</code></li>\n<li><code>xtype</code></li>\n</ul>\n\n\n<p>The supported forms for these keywords are as follows.</p>\n\n<p>Just a string:</p>\n\n<pre><code>requires: 'Foo.thing.Bar',\n//...\n</code></pre>\n\n<p>An array of strings:</p>\n\n<pre><code>requires: [ 'Foo.thing.Bar', 'Foo.other.Thing' ],\n//...\n</code></pre>\n\n<h4>Forms of <code>mixins</code></h4>\n\n<p>Using an object literal, the name given the mixin can be quoted or not:</p>\n\n<pre><code>mixins: {\n    name: 'Foo.bar.Mixin',\n    'other': 'Foo.other.Mixin'\n},\n//...\n</code></pre>\n\n<p>Mixins can also be specified as a String[]:</p>\n\n<pre><code>mixins: [\n    'Foo.bar.Mixin',\n    'Foo.other.Mixin'\n],\n//...\n</code></pre>\n\n<h4>The <code>statics</code> Keyword</h4>\n\n<p>This keyword is used to place properties or methods on the class as opposed to on each of\nthe instances. This must be an object literal.</p>\n\n<pre><code>statics: {\n    // members go here\n},\n// ...\n</code></pre>\n\n<h4>The <code>singleton</code> Keyword</h4>\n\n<p>This keyword was historically only used with a boolean \"true\" value:</p>\n\n<pre><code>singleton: true,\n</code></pre>\n\n<p>The following (redundant) use is also supported:</p>\n\n<pre><code>singleton: false,\n</code></pre>\n\n<h2 id='command_code-section-5'>Overrides</h2>\n\n<p>In Ext JS 4.1.0 and Sencha Touch 2.0, <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a></code> gained the ability to manage overrides.\nHistorically, overrides have been used to patch code to work around bugs or add\nenhancements. This use was complicated with the introduction of the dynamic loader because\nof the timing required to execute the <code><a href=\"#!/api/Ext-method-override\" rel=\"Ext-method-override\" class=\"docClass\">Ext.override</a></code> method. Also, in large applications\nwith many overrides, not all overrides in the code base were need by all pages or builds\n(e.g., if the target class was not required).</p>\n\n<p>All this changed once the class system and loader understood overrides. This trend only\ncontinues with Sencha Cmd. The compiler understands overrides and their dependency effects\nand load-sequence issues.</p>\n\n<p>In the future, the compiler will become even more aggressive at dead-code elimination of\nmethods replaced by an override. Using managed overrides as described below will enable\nthis optimization of your code once available in Sencha Cmd.</p>\n\n<h3>Standard Override Form</h3>\n\n<p>Below is the standard form of an override. The choice of namespace is somewhat arbitrary,\nbut see below for some suggestions.</p>\n\n<pre><code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>('MyApp.patches.grid.Panel', {\n    override: '<a href=\"#!/api/Ext.grid.Panel\" rel=\"Ext.grid.Panel\" class=\"docClass\">Ext.grid.Panel</a>',\n\n    ...\n});\n</code></pre>\n\n<h3>Use Cases</h3>\n\n<p>With the ability to use <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a></code> to manage overrides, new idioms have opened up and\nare actively being leveraged. For exampled in the code generators of\n<a href=\"http://www.sencha.com/products/architect/\">Sencha Architect</a> and internal to the framework,\nto break apart large classes like <code><a href=\"#!/api/Ext.dom.Element\" rel=\"Ext.dom.Element\" class=\"docClass\">Ext.Element</a></code> into more manageable and cohesive pieces.</p>\n\n<h4>Overrides as Patches</h4>\n\n<p>This is the historical use case and hence the most common in practice today.</p>\n\n<p><strong>CAUTION:</strong> Care should be taken when patching code. While the use of override itself is\nsupported, the end result of overriding framework methods is not supported. All overrides\nshould be carefully reviewed whenever upgrading to a new framework version.</p>\n\n<p>That said, it is, at times, necessary to override framework methods. The most common case\nfor this to fix a bug. The Standard Override Form is ideal in this case. In fact, Sencha\nSupport will at times provide customer with patches in this form. Once provided, however,\nmanaging such patches and removing them when no longer needed is a matter for the review\nprocess previously mentioned.</p>\n\n<p>Naming Recommendation:</p>\n\n<ul>\n<li><p>Organize patches in a namespace associated with the top-level namespace of the target.\nFor example, \"MyApp.patches\" targets the \"Ext\" namespace. If third party code is involved\nthen perhaps another level or namespace should be chosen to correspond to its top-level\nnamespace. From there, name the override using a matching name and sub-namespace. In the\nabove example:</p>\n\n<p>   (Ext -> MyApp.patches).grid.Panel</p></li>\n</ul>\n\n\n<h4>Overrides as Partial Classes</h4>\n\n<p>When dealing with code generation (as in Sencha Architect), it is common for a class to\nconsist of two parts: one machine generated and one human edited. In some languages, there\nis formal support for the notion of a \"partial class\" or a class-in-two-parts.</p>\n\n<p>Using an override, you can manage this cleanly:</p>\n\n<p>In ./foo/bar/Thing.js:</p>\n\n<pre><code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>('Foo.bar.Thing', {\n    // NOTE: This class is generated - DO NOT EDIT...\n\n    requires: [\n        'Foo.bar.custom.Thing'\n    ],\n\n    method: function () {\n        // some generated method\n    },\n\n    ...\n});\n</code></pre>\n\n<p>In ./foo/bar/custom/Thing.js:</p>\n\n<pre><code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>('Foo.bar.custom.Thing', {\n    override: 'Foo.bar.Thing',\n\n    method: function () {\n        this.callParent(); // calls generated method\n        ...\n    },\n\n    ...\n});\n</code></pre>\n\n<p>Naming Recommendations:</p>\n\n<ul>\n<li>Organize generated vs. hand-edited code by namespace.</li>\n<li>If not by namespace, consider a common base name with a suffix on one or the other\n(e.g., \"Foo.bar.ThingOverride\" or \"Foo.bar.ThingGenerated\") so that the parts of a class\ncollate together in listings.</li>\n</ul>\n\n\n<h4>Overrides as Aspects</h4>\n\n<p>A common problem for base classes in object-oriented designs is the \"fat base class\". This\nhappens because some behaviors apply across all classes. When these behaviors (or features)\nare not needed, however, they cannot be readily removed if they are implemented as part of\nsome large base class.</p>\n\n<p>Using overrides, these features can be collected in their own hierarchy and then <code>requires</code>\ncan be used to select these features when needed.</p>\n\n<p>In ./foo/feature/Component.js:</p>\n\n<pre><code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>('Foo.feature.Component', {\n    override: '<a href=\"#!/api/Ext.Component\" rel=\"Ext.Component\" class=\"docClass\">Ext.Component</a>',\n\n    ...\n});\n</code></pre>\n\n<p>In ./foo/feature/grid/Panel.js:</p>\n\n<pre><code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a>('Foo.feature.grid.Panel', {\n    override: '<a href=\"#!/api/Ext.grid.Panel\" rel=\"Ext.grid.Panel\" class=\"docClass\">Ext.grid.Panel</a>',\n\n    requires: [\n        'Foo.feature.Component' // since overrides do not \"extend\" each other\n    ],\n\n    ...\n});\n</code></pre>\n\n<p>This feature can be used now by requiring it:</p>\n\n<pre><code>...\nrequires: [\n    'Foo.feature.grid.Panel'\n]\n</code></pre>\n\n<p>Or with a proper \"bootstrap\" file (see <a href=\"#/guide/command_workspace\">Workspaces in Sencha Cmd</a>\nor <a href=\"#/guide/command_app_single\">Single-Page Ext JS Apps</a>):</p>\n\n<pre><code>...\nrequires: [\n    'Foo.feature.*'\n]\n</code></pre>\n\n<p>Naming Recommendation:</p>\n\n<ul>\n<li>Organize generated vs. hand-edited code by namespace. This enables use of wildcards to\nbring in all aspects of the feature.</li>\n</ul>\n\n\n<h3>Using <code>requires</code> and <code>uses</code> in an Override</h3>\n\n<p>These keywords are supported in overrides. Use of <code>requires</code> may limit the compiler's\nability to reorder the code of an override.</p>\n\n<h3>Using <code>callParent</code> and <code>callSuper</code></h3>\n\n<p>To support all of these new uses cases, <code>callParent</code> was enhanced in Ext JS 4.0 and Sencha\nTouch 2.0 to \"call the next method\". The \"next method\" may be an overridden method or an\ninherited method. As long as there is a next method, <code>callParent</code> will call it.</p>\n\n<p>Another way to view this is that <code>callParent</code> works the same for all forms of <code><a href=\"#!/api/Ext-method-define\" rel=\"Ext-method-define\" class=\"docClass\">Ext.define</a></code>,\nbe they classes or overrides.</p>\n\n<p>While this helped in some areas, it unfortunately made bypassing the original method (as a\npatch or bug fix) more difficult. So in Ext JS 4.1.1a, Ext JS 4.1.2a and Sencha Touch 2.1,\nthere is now a method named <code>callSuper</code> that can be used to bypass an overridden method.</p>\n\n<p>In future releases, the compiler will use this semantic difference to perform dead-code\nelimination of overridden methods.</p>\n\n<h2 id='command_code-section-6'>Conclusion</h2>\n\n<p>As Sencha Cmd continues to evolve, it will continue to introduce new diagnostic messages\nto help point out deviations from these guidelines.</p>\n\n<p>A good place to start is to see how this information can help inform your own internal\ncode style guidelines and practices.</p>\n"});