imageIn April of this year, as part of the rollout of Ext JS 4.2 and the new Neptune theme, we introduced support for packages in Sencha Cmd 3.1. At that time, packages were primarily targeted at themes but obviously themes are not the only use case for self-contained bundles of JavaScript, Sass and resources. In this article, we’ll dig into some of the inner workings of packages and see how to leverage them for perhaps their most common use case: to share code between applications.

Setting The Stage

In Sencha Cmd, applications exist in a Workspace. A Workspace is just a root folder of your choice where common things like applications, packages and Sencha frameworks reside. It is common to pick the root folder in source control to be the Workspace, but this is not required. For this article, we will create a test Workspace in an empty folder:

To get the ball rolling, let’s set up two Ext JS applications in this Workspace. By default, when we run “sencha generate app” we will get a Workspace as well as the application, and they will be in the same folder. That is, unless we generate the application in an existing Workspace, like the one we just created.

The following commands point Sencha Cmd at the Ext JS 4.2.1 downloaded and expanded zip file. The first Ext JS application we generate in the Workspace copies the necessary subset of the Ext JS SDK (or “framework”) into the “ext” folder. The second generated application does not need to do this as it will share the framework already in the Workspace.

Now, we have a Workspace, a subset of Ext JS and two empty applications in a folder structure that looks like this:

Let’s Make A Package

Packages can be generated in a manner similar to applications like so:

The key difference here is that the new package is placed in the “packages” folder:

To make use of this package in our applications, we add it to their respective “app.json” files in the “requires” array:

What Does That Do?

The most obvious thing it does is incorporate the JavaScript payload from the “common” package into the build for these applications. It does it at the level of the “classpath”. In Sencha Cmd, each application (and package) has its own classpath. By default, the applications both have this setting in their respective “.sencha/app/sencha.cfg” files:

And a package has this setting in its “.sencha/package/sencha.cfg” file:

By virtue of the “requires” in “app.json”, the “package.classpath” for each required package is added (along with the “app.classpath”) to the compiler’s internal (total) classpath. All JavaScript files in these locations are scanned by the compiler and available for use.

To streamline these settings for use by applications, the information gleaned by the compiler is exported into what is called the “bootstrap”. If you are already familiar with the “Ext.Loader.setConfig” or “Ext.Loader.setPath” APIs, you won’t be needing them! Instead, you’ll find all the paths needed (and more) in your application’s “bootstrap.js” file.

This is not all that the package dependency accomplishes but that is enough for starters.

Using The Package

What’s next? A common (incorrect) assumption is that we must first build the package using “sencha package build” before it is useful to our applications. In fact, all that Sencha Cmd needs to use a package is knowledge of its classpath.

That means that the correct answer to this question is: we need to “refresh” the application’s bootstrap. If you are using the (new to Cmd v4) “sencha app watch” command then all of the necessary steps will be taken by restarting the watch. Adding package dependencies is not something that “sencha app watch” currently handles internally, so the manual restart is needed for now. As new classes are added to this package, however, app watch will detect these and automatically refresh the bootstrap.

While Sencha Cmd requires Java 6 for most functionality, “sencha app watch” depends on Java 7. If this is an issue, you can alternatively use the command that was available prior to Cmd v4: “sencha app refresh”. This command does exactly and only what is needed for this case. In Cmd v4, this is now just a convenient way to run the “refresh” target of the app build. In other words, “sencha app build” will also refresh the bootstrap… as well as build the Sass and a few other things.

What Does “sencha package build” Do?

The generated build script for packages (the implementation of “sencha package build”) handles two use cases: 1) produce a build of the package source for non-Cmd applications (similar to the “ext-all.js” file) and 2) prepare the package for distribution. Neither of these is required for a local package in a Workspace with Cmd-based applications, so we can ignore package builds entirely for this scenario.

These topics are covered thoroughly in the guides, so check them out for more details.

Packages With Components or Views

We have a Workspace with two (mostly) empty applications, the Ext JS SDK and a package named “common”. The applications are prepared to use any code we add to the common package, but things get interesting when we want to share complex things like custom components or perhaps Views for an MVC application. The complications come from the two “other” types of content needed to share such things: styles and resources (such as images).

Sharing Sass

Given that packages were originally designed to solve the requirements of themes, it should come as no surprise that packages can contain Sass source code (the dialect of “CSS++” used by Sencha frameworks) and that Sencha Cmd understands how to incorporate this code into your application’s build.

Prior to packages, there was no clean way to know the relationship between Sass source files and their corresponding components. This meant manually controlling the inclusion of the *.scss files you needed, based on the current state of the application’s JavaScript code.

With packages, however, Sencha Cmd provides the logic to link JavaScript classes to their associated Sass code. This is done by class name correspondence. For example, the “Ext.button.Button” class would have an associated “button/Button.scss” file or files, depending on your theme.

This has been the recommended way to organize the JavaScript code for these classes, which makes it a natural choice for these other source files. By virtue of this correspondence, the generated CSS file will only contain the styles for those components actually used by your application, and they will cascade from base class to derived class, as you would expect.

There are many other details related to this correspondence covered in the Themes guide. This aspect of packages does not currently apply to Sencha Touch applications.

Sharing Resources

One of the more interesting challenges for composing applications from multiple packages is how to isolate their respective resources. When two packages are written, they will not likely be aware of each other, and yet, they must somehow coexist in applications that want to use them together. In JavaScript, this is done by namespacing, but what about images?

In Ext JS themes, there is a Sass function used to resolve image paths given just the filename: theme-background-image. This function applies the proper prefix and even file type suffix (“.gif” or “.png”) based on other configuration properties. It is used like this:

For themes, the “resources” folders of the packages in the theme’s inheritance hierarchy are flattened on top of each other. This allows derived themes to selectively override image assets from base themes. All of these resources are copied into the “resources” folder of the built application, typically in “resources/images”. That is:

The Sass is compiled to produce the CSS file in the “resources” folder. This means that the relative paths generated for theme images will be optimally short: “images/foo.gif”. This is another way Cmd helps cut your download size.

This same method also works for non-theme packages. The only difference is that the “resources” folder for such packages is copied into a subfolder of the application’s “build/resources” folder named by the package:

Image paths for non-theme images will be slightly longer: “common/images/foo.gif”.

Does Sencha App Watch Handle All This?

Yes. As files are added or modified in any of the “sass” and “resources” folders, they are automatically picked up. Changes to Sass files trigger incremental Compass builds. Likewise changes to any of the resources folders are synchronized to the build/resources folder. In a matter of a few seconds after the file system settles, the bits should be ready for a reload in the browser.

Packages In Action

Here are some links to Git repositories where you can see some of these things and more in use:

  • This repository has an example theme package and a custom button component package.
  • This repository has the custom button component that uses theme base colors, provides its own Sass mixin and an example application that shows off two different “UIs” made from the mixin.
  • This repository contains two Workspaces with different arrangements of Sencha Touch and Ext JS applications sharing code between each other using packages.

For general information about packages, you can check out the Packages guide.

.right, .alignright float: right; margin: 0 0 10px 10px;
.left, .alignleft float: left; margin: 0 10px 10px 0;

Original article:

Understanding Sencha Cmd Packages